We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
After i3wm reload on first click error happens: JSONDecodeError: Expecting value: line 1 column 2 (char 1)  [happens with custom module]
**Describe the bug**
Error after reloading i3wm first click fails with error:

```
2022-01-17 21:03:22 WARNING Event failed.
2022-01-17 21:03:22 INFO Traceback
JSONDecodeError: Expecting value: line 1 column 2 (char 1)
  File "/home/valdur/arendus/py3status-valdur55/py3status/events.py", line 281, in run
    event = loads(event_str)
  File "/usr/lib/python3.8/json/__init__.py", line 357, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python3.8/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python3.8/json/decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
2022-01-17 21:03:22 ERROR Event failed. Please try to fix this and reload i3wm (Mod+Shift+R)
```
Without debugger values are:
(self.io, sys.stdin, line)
(<_io.BufferedReader name=5>, <_io.TextIOWrapper name='<stdin>' mode='r' encoding='utf-8'>, b'[')

With debugger loaded:
(<_io.TextIOWrapper name='<stdin>' mode='r' encoding='utf-8'>, <_pydev_bundle.pydev_stdin.DebugConsoleStdIn object at 0x7fd05220ef70>, '')

Pydevd modifies **sys.stdin** and puts original one as **sys.stdin.original_stdin**

**Your py3status version**
3.40

**To Reproduce**
Steps to reproduce the behavior along with your py3status configuration (filter out any private values):
1. Add module . (https://gist.github.com/valdur55/6879f298095b8c54883eb01f8392ba55) and install pydevd module (IDE not needed)
  I am using it for connecting to IDE remote debugger session so I can use module panel and do debug actions on IDE.
2. Enable module by adding order += pydev_debug
3. Run py3status in panel
4. Click on module/panes and see error notification.

**Expected behavior**
Error should not appear.



--- 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/events.py`
Content:
```
1 import select
2 import sys
3 
4 from threading import Thread
5 from subprocess import Popen, PIPE
6 from json import loads
7 from shlex import quote as shell_quote
8 
9 from py3status.profiling import profile
10 
11 
12 class IOPoller:
13     """
14     This class implements a predictive and timing-out I/O reader
15     using select and the poll() mechanism for greater compatibility.
16     """
17 
18     def __init__(self, io, eventmask=select.POLLIN):
19         """
20         Our default is to read (POLLIN) the specified 'io' file descriptor.
21         """
22         self.io = io
23         self.poller = select.poll()
24         self.poller.register(io, eventmask)
25 
26     def readline(self, timeout=500):
27         """
28         Try to read our I/O for 'timeout' milliseconds, return None otherwise.
29         This makes calling and reading I/O non blocking !
30         """
31         poll_result = self.poller.poll(timeout)
32         if poll_result:
33             line = self.io.readline().strip()
34             if self.io == sys.stdin and line == "[":
35                 # skip first event line wrt issue #19
36                 line = self.io.readline().strip()
37             try:
38                 # python3 compatibility code
39                 line = line.decode()
40             except (AttributeError, UnicodeDecodeError):
41                 pass
42             return line
43         else:
44             return None
45 
46 
47 class EventTask:
48     """
49     A simple task that can be run by the scheduler.
50     """
51 
52     def __init__(self, module_name, event, default_event, events_thread):
53         self.events_thread = events_thread
54         self.module_full_name = module_name
55         self.default_event = default_event
56         self.event = event
57 
58     def run(self):
59         self.events_thread.process_event(
60             self.module_full_name, self.event, self.default_event
61         )
62 
63 
64 class EventClickTask:
65     """
66     A task to run an external on_click event
67     """
68 
69     def __init__(self, module_name, event, events_thread, command):
70         self.events_thread = events_thread
71         self.module_name = module_name
72         self.command = command
73         self.event = event
74 
75     def run(self):
76         self.events_thread.on_click_dispatcher(
77             self.module_name, self.event, self.command
78         )
79 
80 
81 class Events(Thread):
82     """
83     This class is responsible for dispatching event JSONs sent by the i3bar.
84     """
85 
86     def __init__(self, py3_wrapper):
87         """
88         We need to poll stdin to receive i3bar messages.
89         """
90         Thread.__init__(self)
91         self.config = py3_wrapper.config
92         self.error = None
93         self.py3_config = py3_wrapper.config["py3_config"]
94         self.modules = py3_wrapper.modules
95         self.on_click = self.py3_config["on_click"]
96         self.output_modules = py3_wrapper.output_modules
97         self.poller_inp = IOPoller(sys.stdin)
98         self.py3_wrapper = py3_wrapper
99 
100     def get_module_text(self, module_name, event):
101         """
102         Get the full text for the module as well as the partial text if the
103         module is a composite.  Partial text is the text for just the single
104         section of a composite.
105         """
106         index = event.get("index")
107         module_info = self.py3_wrapper.output_modules.get(module_name)
108         output = module_info["module"].get_latest()
109         full_text = "".join(out["full_text"] for out in output)
110 
111         partial = None
112         if index is not None:
113             if isinstance(index, int):
114                 partial = output[index]
115             else:
116                 for item in output:
117                     if item.get("index") == index:
118                         partial = item
119                         break
120         if partial:
121             partial_text = partial["full_text"]
122         else:
123             partial_text = full_text
124         return full_text, partial_text
125 
126     def on_click_dispatcher(self, module_name, event, command):
127         """
128         Dispatch on_click config parameters to either:
129             - Our own methods for special py3status commands (listed below)
130             - The i3-msg program which is part of i3wm
131         """
132         if command is None:
133             return
134         elif command == "refresh_all":
135             self.py3_wrapper.refresh_modules()
136         elif command == "refresh":
137             self.py3_wrapper.refresh_modules(module_name)
138         else:
139             # In commands we are able to use substitutions for the text output
140             # of a module
141             if "$OUTPUT" in command or "$OUTPUT_PART" in command:
142                 full_text, partial_text = self.get_module_text(module_name, event)
143                 command = command.replace("$OUTPUT_PART", shell_quote(partial_text))
144                 command = command.replace("$OUTPUT", shell_quote(full_text))
145 
146             # this is a i3 message
147             self.wm_msg(module_name, command)
148             # to make the bar more responsive to users we ask for a refresh
149             # of the module or of i3status if the module is an i3status one
150             self.py3_wrapper.refresh_modules(module_name)
151 
152     def wm_msg(self, module_name, command):
153         """
154         Execute the message with i3-msg or swaymsg and log its output.
155         """
156         wm_msg = self.config["wm"]["msg"]
157         pipe = Popen([wm_msg, command], stdout=PIPE)
158         self.py3_wrapper.log(
159             '{} module="{}" command="{}" stdout={}'.format(
160                 wm_msg, module_name, command, pipe.stdout.read()
161             )
162         )
163 
164     def process_event(self, module_name, event, default_event=False):
165         """
166         Process the event for the named module.
167         Events may have been declared in i3status.conf, modules may have
168         on_click() functions. There is a default middle click event etc.
169         """
170 
171         # get the module that the event is for
172         module_info = self.output_modules.get(module_name)
173 
174         # if module is a py3status one call it.
175         if module_info["type"] == "py3status":
176             module = module_info["module"]
177             module.click_event(event)
178             if self.config["debug"]:
179                 self.py3_wrapper.log(f"dispatching event {event}")
180 
181             # to make the bar more responsive to users we refresh the module
182             # unless the on_click event called py3.prevent_refresh()
183             if not module.prevent_refresh:
184                 self.py3_wrapper.refresh_modules(module_name)
185                 default_event = False
186 
187         if default_event:
188             # default button 2 action is to clear this method's cache
189             if self.config["debug"]:
190                 self.py3_wrapper.log(f"dispatching default event {event}")
191             self.py3_wrapper.refresh_modules(module_name)
192 
193         # find container that holds the module and call its onclick
194         module_groups = self.py3_config[".module_groups"]
195         containers = module_groups.get(module_name, [])
196         for container in containers:
197             self.process_event(container, event)
198 
199     def dispatch_event(self, event):
200         """
201         Takes an event dict.  Logs the event if needed and cleans up the dict
202         such as setting the index needed for composits.
203         """
204         if self.config["debug"]:
205             self.py3_wrapper.log(f"received event {event}")
206 
207         # usage variables
208         event["index"] = event.get("index", "")
209         instance = event.get("instance", "")
210         name = event.get("name", "")
211 
212         # composites have an index which is passed to i3bar with
213         # the instance.  We need to separate this out here and
214         # clean up the event.  If index
215         # is an integer type then cast it as such.
216         if " " in instance:
217             instance, index = instance.split(" ", 1)
218             try:
219                 index = int(index)
220             except ValueError:
221                 pass
222             event["index"] = index
223             event["instance"] = instance
224 
225         if self.config["debug"]:
226             self.py3_wrapper.log(
227                 'trying to dispatch event to module "{}"'.format(
228                     f"{name} {instance}".strip()
229                 )
230             )
231 
232         # guess the module config name
233         module_name = f"{name} {instance}".strip()
234 
235         default_event = False
236         module_info = self.output_modules.get(module_name)
237         module = module_info["module"]
238         # execute any configured i3-msg command
239         # we do not do this for containers
240         # modules that have failed do not execute their config on_click
241         if module.allow_config_clicks:
242             button = event.get("button", 0)
243             on_click = self.on_click.get(module_name, {}).get(str(button))
244             if on_click:
245                 task = EventClickTask(module_name, event, self, on_click)
246                 self.py3_wrapper.timeout_queue_add(task)
247             # otherwise setup default action on button 2 press
248             elif button == 2:
249                 default_event = True
250 
251         # do the work
252         task = EventTask(module_name, event, default_event, self)
253         self.py3_wrapper.timeout_queue_add(task)
254 
255     @profile
256     def run(self):
257         """
258         Wait for an i3bar JSON event, then find the right module to dispatch
259         the message to based on the 'name' and 'instance' of the event.
260 
261         In case the module does NOT support click_events, the default
262         implementation is to clear the module's cache
263         when the MIDDLE button (2) is pressed on it.
264 
265         Example event:
266         {'y': 13, 'x': 1737, 'button': 1, 'name': 'empty', 'instance': 'first'}
267         """
268         try:
269             while self.py3_wrapper.running:
270                 event_str = self.poller_inp.readline()
271                 if not event_str:
272                     continue
273                 try:
274                     # remove leading comma if present
275                     if event_str[0] == ",":
276                         event_str = event_str[1:]
277                     event = loads(event_str)
278                     self.dispatch_event(event)
279                 except Exception:
280                     self.py3_wrapper.report_exception("Event failed")
281         except:  # noqa e722
282             err = "Events thread died, click events are disabled."
283             self.py3_wrapper.report_exception(err, notify_user=False)
284             self.py3_wrapper.notify_user(err, level="warning")
285
```
--- 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/events.py b/py3status/events.py
--- a/py3status/events.py
+++ b/py3status/events.py
@@ -31,7 +31,11 @@
         poll_result = self.poller.poll(timeout)
         if poll_result:
             line = self.io.readline().strip()
-            if self.io == sys.stdin and line == "[":
+            # When using pydev.deugger sys.stdin gets overwritten and placed into sys.stdin.original_stdin issue #2090
+            if (
+                self.io == getattr(sys.stdin, "original_stdin", sys.stdin)
+                and line == "["
+            ):
                 # skip first event line wrt issue #19
                 line = self.io.readline().strip()
             try:

{"golden_diff": "diff --git a/py3status/events.py b/py3status/events.py\n--- a/py3status/events.py\n+++ b/py3status/events.py\n@@ -31,7 +31,11 @@\n         poll_result = self.poller.poll(timeout)\n         if poll_result:\n             line = self.io.readline().strip()\n-            if self.io == sys.stdin and line == \"[\":\n+            # When using pydev.deugger sys.stdin gets overwritten and placed into sys.stdin.original_stdin issue #2090\n+            if (\n+                self.io == getattr(sys.stdin, \"original_stdin\", sys.stdin)\n+                and line == \"[\"\n+            ):\n                 # skip first event line wrt issue #19\n                 line = self.io.readline().strip()\n             try:\n", "issue": "After i3wm reload on first click error happens: JSONDecodeError: Expecting value: line 1 column 2 (char 1)  [happens with custom module]\n**Describe the bug**\r\nError after reloading i3wm first click fails with error:\r\n\r\n```\r\n2022-01-17 21:03:22 WARNING Event failed.\r\n2022-01-17 21:03:22 INFO Traceback\r\nJSONDecodeError: Expecting value: line 1 column 2 (char 1)\r\n  File \"/home/valdur/arendus/py3status-valdur55/py3status/events.py\", line 281, in run\r\n    event = loads(event_str)\r\n  File \"/usr/lib/python3.8/json/__init__.py\", line 357, in loads\r\n    return _default_decoder.decode(s)\r\n  File \"/usr/lib/python3.8/json/decoder.py\", line 337, in decode\r\n    obj, end = self.raw_decode(s, idx=_w(s, 0).end())\r\n  File \"/usr/lib/python3.8/json/decoder.py\", line 355, in raw_decode\r\n    raise JSONDecodeError(\"Expecting value\", s, err.value) from None\r\n2022-01-17 21:03:22 ERROR Event failed. Please try to fix this and reload i3wm (Mod+Shift+R)\r\n```\r\nWithout debugger values are:\r\n(self.io, sys.stdin, line)\r\n(<_io.BufferedReader name=5>, <_io.TextIOWrapper name='<stdin>' mode='r' encoding='utf-8'>, b'[')\r\n\r\nWith debugger loaded:\r\n(<_io.TextIOWrapper name='<stdin>' mode='r' encoding='utf-8'>, <_pydev_bundle.pydev_stdin.DebugConsoleStdIn object at 0x7fd05220ef70>, '')\r\n\r\nPydevd modifies **sys.stdin** and puts original one as **sys.stdin.original_stdin**\r\n\r\n**Your py3status version**\r\n3.40\r\n\r\n**To Reproduce**\r\nSteps to reproduce the behavior along with your py3status configuration (filter out any private values):\r\n1. Add module . (https://gist.github.com/valdur55/6879f298095b8c54883eb01f8392ba55) and install pydevd module (IDE not needed)\r\n  I am using it for connecting to IDE remote debugger session so I can use module panel and do debug actions on IDE.\r\n2. Enable module by adding order += pydev_debug\r\n3. Run py3status in panel\r\n4. Click on module/panes and see error notification.\r\n\r\n**Expected behavior**\r\nError should not appear.\r\n\r\n\n", "before_files": [{"content": "import select\nimport sys\n\nfrom threading import Thread\nfrom subprocess import Popen, PIPE\nfrom json import loads\nfrom shlex import quote as shell_quote\n\nfrom py3status.profiling import profile\n\n\nclass IOPoller:\n    \"\"\"\n    This class implements a predictive and timing-out I/O reader\n    using select and the poll() mechanism for greater compatibility.\n    \"\"\"\n\n    def __init__(self, io, eventmask=select.POLLIN):\n        \"\"\"\n        Our default is to read (POLLIN) the specified 'io' file descriptor.\n        \"\"\"\n        self.io = io\n        self.poller = select.poll()\n        self.poller.register(io, eventmask)\n\n    def readline(self, timeout=500):\n        \"\"\"\n        Try to read our I/O for 'timeout' milliseconds, return None otherwise.\n        This makes calling and reading I/O non blocking !\n        \"\"\"\n        poll_result = self.poller.poll(timeout)\n        if poll_result:\n            line = self.io.readline().strip()\n            if self.io == sys.stdin and line == \"[\":\n                # skip first event line wrt issue #19\n                line = self.io.readline().strip()\n            try:\n                # python3 compatibility code\n                line = line.decode()\n            except (AttributeError, UnicodeDecodeError):\n                pass\n            return line\n        else:\n            return None\n\n\nclass EventTask:\n    \"\"\"\n    A simple task that can be run by the scheduler.\n    \"\"\"\n\n    def __init__(self, module_name, event, default_event, events_thread):\n        self.events_thread = events_thread\n        self.module_full_name = module_name\n        self.default_event = default_event\n        self.event = event\n\n    def run(self):\n        self.events_thread.process_event(\n            self.module_full_name, self.event, self.default_event\n        )\n\n\nclass EventClickTask:\n    \"\"\"\n    A task to run an external on_click event\n    \"\"\"\n\n    def __init__(self, module_name, event, events_thread, command):\n        self.events_thread = events_thread\n        self.module_name = module_name\n        self.command = command\n        self.event = event\n\n    def run(self):\n        self.events_thread.on_click_dispatcher(\n            self.module_name, self.event, self.command\n        )\n\n\nclass Events(Thread):\n    \"\"\"\n    This class is responsible for dispatching event JSONs sent by the i3bar.\n    \"\"\"\n\n    def __init__(self, py3_wrapper):\n        \"\"\"\n        We need to poll stdin to receive i3bar messages.\n        \"\"\"\n        Thread.__init__(self)\n        self.config = py3_wrapper.config\n        self.error = None\n        self.py3_config = py3_wrapper.config[\"py3_config\"]\n        self.modules = py3_wrapper.modules\n        self.on_click = self.py3_config[\"on_click\"]\n        self.output_modules = py3_wrapper.output_modules\n        self.poller_inp = IOPoller(sys.stdin)\n        self.py3_wrapper = py3_wrapper\n\n    def get_module_text(self, module_name, event):\n        \"\"\"\n        Get the full text for the module as well as the partial text if the\n        module is a composite.  Partial text is the text for just the single\n        section of a composite.\n        \"\"\"\n        index = event.get(\"index\")\n        module_info = self.py3_wrapper.output_modules.get(module_name)\n        output = module_info[\"module\"].get_latest()\n        full_text = \"\".join(out[\"full_text\"] for out in output)\n\n        partial = None\n        if index is not None:\n            if isinstance(index, int):\n                partial = output[index]\n            else:\n                for item in output:\n                    if item.get(\"index\") == index:\n                        partial = item\n                        break\n        if partial:\n            partial_text = partial[\"full_text\"]\n        else:\n            partial_text = full_text\n        return full_text, partial_text\n\n    def on_click_dispatcher(self, module_name, event, command):\n        \"\"\"\n        Dispatch on_click config parameters to either:\n            - Our own methods for special py3status commands (listed below)\n            - The i3-msg program which is part of i3wm\n        \"\"\"\n        if command is None:\n            return\n        elif command == \"refresh_all\":\n            self.py3_wrapper.refresh_modules()\n        elif command == \"refresh\":\n            self.py3_wrapper.refresh_modules(module_name)\n        else:\n            # In commands we are able to use substitutions for the text output\n            # of a module\n            if \"$OUTPUT\" in command or \"$OUTPUT_PART\" in command:\n                full_text, partial_text = self.get_module_text(module_name, event)\n                command = command.replace(\"$OUTPUT_PART\", shell_quote(partial_text))\n                command = command.replace(\"$OUTPUT\", shell_quote(full_text))\n\n            # this is a i3 message\n            self.wm_msg(module_name, command)\n            # to make the bar more responsive to users we ask for a refresh\n            # of the module or of i3status if the module is an i3status one\n            self.py3_wrapper.refresh_modules(module_name)\n\n    def wm_msg(self, module_name, command):\n        \"\"\"\n        Execute the message with i3-msg or swaymsg and log its output.\n        \"\"\"\n        wm_msg = self.config[\"wm\"][\"msg\"]\n        pipe = Popen([wm_msg, command], stdout=PIPE)\n        self.py3_wrapper.log(\n            '{} module=\"{}\" command=\"{}\" stdout={}'.format(\n                wm_msg, module_name, command, pipe.stdout.read()\n            )\n        )\n\n    def process_event(self, module_name, event, default_event=False):\n        \"\"\"\n        Process the event for the named module.\n        Events may have been declared in i3status.conf, modules may have\n        on_click() functions. There is a default middle click event etc.\n        \"\"\"\n\n        # get the module that the event is for\n        module_info = self.output_modules.get(module_name)\n\n        # if module is a py3status one call it.\n        if module_info[\"type\"] == \"py3status\":\n            module = module_info[\"module\"]\n            module.click_event(event)\n            if self.config[\"debug\"]:\n                self.py3_wrapper.log(f\"dispatching event {event}\")\n\n            # to make the bar more responsive to users we refresh the module\n            # unless the on_click event called py3.prevent_refresh()\n            if not module.prevent_refresh:\n                self.py3_wrapper.refresh_modules(module_name)\n                default_event = False\n\n        if default_event:\n            # default button 2 action is to clear this method's cache\n            if self.config[\"debug\"]:\n                self.py3_wrapper.log(f\"dispatching default event {event}\")\n            self.py3_wrapper.refresh_modules(module_name)\n\n        # find container that holds the module and call its onclick\n        module_groups = self.py3_config[\".module_groups\"]\n        containers = module_groups.get(module_name, [])\n        for container in containers:\n            self.process_event(container, event)\n\n    def dispatch_event(self, event):\n        \"\"\"\n        Takes an event dict.  Logs the event if needed and cleans up the dict\n        such as setting the index needed for composits.\n        \"\"\"\n        if self.config[\"debug\"]:\n            self.py3_wrapper.log(f\"received event {event}\")\n\n        # usage variables\n        event[\"index\"] = event.get(\"index\", \"\")\n        instance = event.get(\"instance\", \"\")\n        name = event.get(\"name\", \"\")\n\n        # composites have an index which is passed to i3bar with\n        # the instance.  We need to separate this out here and\n        # clean up the event.  If index\n        # is an integer type then cast it as such.\n        if \" \" in instance:\n            instance, index = instance.split(\" \", 1)\n            try:\n                index = int(index)\n            except ValueError:\n                pass\n            event[\"index\"] = index\n            event[\"instance\"] = instance\n\n        if self.config[\"debug\"]:\n            self.py3_wrapper.log(\n                'trying to dispatch event to module \"{}\"'.format(\n                    f\"{name} {instance}\".strip()\n                )\n            )\n\n        # guess the module config name\n        module_name = f\"{name} {instance}\".strip()\n\n        default_event = False\n        module_info = self.output_modules.get(module_name)\n        module = module_info[\"module\"]\n        # execute any configured i3-msg command\n        # we do not do this for containers\n        # modules that have failed do not execute their config on_click\n        if module.allow_config_clicks:\n            button = event.get(\"button\", 0)\n            on_click = self.on_click.get(module_name, {}).get(str(button))\n            if on_click:\n                task = EventClickTask(module_name, event, self, on_click)\n                self.py3_wrapper.timeout_queue_add(task)\n            # otherwise setup default action on button 2 press\n            elif button == 2:\n                default_event = True\n\n        # do the work\n        task = EventTask(module_name, event, default_event, self)\n        self.py3_wrapper.timeout_queue_add(task)\n\n    @profile\n    def run(self):\n        \"\"\"\n        Wait for an i3bar JSON event, then find the right module to dispatch\n        the message to based on the 'name' and 'instance' of the event.\n\n        In case the module does NOT support click_events, the default\n        implementation is to clear the module's cache\n        when the MIDDLE button (2) is pressed on it.\n\n        Example event:\n        {'y': 13, 'x': 1737, 'button': 1, 'name': 'empty', 'instance': 'first'}\n        \"\"\"\n        try:\n            while self.py3_wrapper.running:\n                event_str = self.poller_inp.readline()\n                if not event_str:\n                    continue\n                try:\n                    # remove leading comma if present\n                    if event_str[0] == \",\":\n                        event_str = event_str[1:]\n                    event = loads(event_str)\n                    self.dispatch_event(event)\n                except Exception:\n                    self.py3_wrapper.report_exception(\"Event failed\")\n        except:  # noqa e722\n            err = \"Events thread died, click events are disabled.\"\n            self.py3_wrapper.report_exception(err, notify_user=False)\n            self.py3_wrapper.notify_user(err, level=\"warning\")\n", "path": "py3status/events.py"}], "after_files": [{"content": "import select\nimport sys\n\nfrom threading import Thread\nfrom subprocess import Popen, PIPE\nfrom json import loads\nfrom shlex import quote as shell_quote\n\nfrom py3status.profiling import profile\n\n\nclass IOPoller:\n    \"\"\"\n    This class implements a predictive and timing-out I/O reader\n    using select and the poll() mechanism for greater compatibility.\n    \"\"\"\n\n    def __init__(self, io, eventmask=select.POLLIN):\n        \"\"\"\n        Our default is to read (POLLIN) the specified 'io' file descriptor.\n        \"\"\"\n        self.io = io\n        self.poller = select.poll()\n        self.poller.register(io, eventmask)\n\n    def readline(self, timeout=500):\n        \"\"\"\n        Try to read our I/O for 'timeout' milliseconds, return None otherwise.\n        This makes calling and reading I/O non blocking !\n        \"\"\"\n        poll_result = self.poller.poll(timeout)\n        if poll_result:\n            line = self.io.readline().strip()\n            # When using pydev.deugger sys.stdin gets overwritten and placed into sys.stdin.original_stdin issue #2090\n            if (\n                self.io == getattr(sys.stdin, \"original_stdin\", sys.stdin)\n                and line == \"[\"\n            ):\n                # skip first event line wrt issue #19\n                line = self.io.readline().strip()\n            try:\n                # python3 compatibility code\n                line = line.decode()\n            except (AttributeError, UnicodeDecodeError):\n                pass\n            return line\n        else:\n            return None\n\n\nclass EventTask:\n    \"\"\"\n    A simple task that can be run by the scheduler.\n    \"\"\"\n\n    def __init__(self, module_name, event, default_event, events_thread):\n        self.events_thread = events_thread\n        self.module_full_name = module_name\n        self.default_event = default_event\n        self.event = event\n\n    def run(self):\n        self.events_thread.process_event(\n            self.module_full_name, self.event, self.default_event\n        )\n\n\nclass EventClickTask:\n    \"\"\"\n    A task to run an external on_click event\n    \"\"\"\n\n    def __init__(self, module_name, event, events_thread, command):\n        self.events_thread = events_thread\n        self.module_name = module_name\n        self.command = command\n        self.event = event\n\n    def run(self):\n        self.events_thread.on_click_dispatcher(\n            self.module_name, self.event, self.command\n        )\n\n\nclass Events(Thread):\n    \"\"\"\n    This class is responsible for dispatching event JSONs sent by the i3bar.\n    \"\"\"\n\n    def __init__(self, py3_wrapper):\n        \"\"\"\n        We need to poll stdin to receive i3bar messages.\n        \"\"\"\n        Thread.__init__(self)\n        self.config = py3_wrapper.config\n        self.error = None\n        self.py3_config = py3_wrapper.config[\"py3_config\"]\n        self.modules = py3_wrapper.modules\n        self.on_click = self.py3_config[\"on_click\"]\n        self.output_modules = py3_wrapper.output_modules\n        self.poller_inp = IOPoller(sys.stdin)\n        self.py3_wrapper = py3_wrapper\n\n    def get_module_text(self, module_name, event):\n        \"\"\"\n        Get the full text for the module as well as the partial text if the\n        module is a composite.  Partial text is the text for just the single\n        section of a composite.\n        \"\"\"\n        index = event.get(\"index\")\n        module_info = self.py3_wrapper.output_modules.get(module_name)\n        output = module_info[\"module\"].get_latest()\n        full_text = \"\".join(out[\"full_text\"] for out in output)\n\n        partial = None\n        if index is not None:\n            if isinstance(index, int):\n                partial = output[index]\n            else:\n                for item in output:\n                    if item.get(\"index\") == index:\n                        partial = item\n                        break\n        if partial:\n            partial_text = partial[\"full_text\"]\n        else:\n            partial_text = full_text\n        return full_text, partial_text\n\n    def on_click_dispatcher(self, module_name, event, command):\n        \"\"\"\n        Dispatch on_click config parameters to either:\n            - Our own methods for special py3status commands (listed below)\n            - The i3-msg program which is part of i3wm\n        \"\"\"\n        if command is None:\n            return\n        elif command == \"refresh_all\":\n            self.py3_wrapper.refresh_modules()\n        elif command == \"refresh\":\n            self.py3_wrapper.refresh_modules(module_name)\n        else:\n            # In commands we are able to use substitutions for the text output\n            # of a module\n            if \"$OUTPUT\" in command or \"$OUTPUT_PART\" in command:\n                full_text, partial_text = self.get_module_text(module_name, event)\n                command = command.replace(\"$OUTPUT_PART\", shell_quote(partial_text))\n                command = command.replace(\"$OUTPUT\", shell_quote(full_text))\n\n            # this is a i3 message\n            self.wm_msg(module_name, command)\n            # to make the bar more responsive to users we ask for a refresh\n            # of the module or of i3status if the module is an i3status one\n            self.py3_wrapper.refresh_modules(module_name)\n\n    def wm_msg(self, module_name, command):\n        \"\"\"\n        Execute the message with i3-msg or swaymsg and log its output.\n        \"\"\"\n        wm_msg = self.config[\"wm\"][\"msg\"]\n        pipe = Popen([wm_msg, command], stdout=PIPE)\n        self.py3_wrapper.log(\n            '{} module=\"{}\" command=\"{}\" stdout={}'.format(\n                wm_msg, module_name, command, pipe.stdout.read()\n            )\n        )\n\n    def process_event(self, module_name, event, default_event=False):\n        \"\"\"\n        Process the event for the named module.\n        Events may have been declared in i3status.conf, modules may have\n        on_click() functions. There is a default middle click event etc.\n        \"\"\"\n\n        # get the module that the event is for\n        module_info = self.output_modules.get(module_name)\n\n        # if module is a py3status one call it.\n        if module_info[\"type\"] == \"py3status\":\n            module = module_info[\"module\"]\n            module.click_event(event)\n            if self.config[\"debug\"]:\n                self.py3_wrapper.log(f\"dispatching event {event}\")\n\n            # to make the bar more responsive to users we refresh the module\n            # unless the on_click event called py3.prevent_refresh()\n            if not module.prevent_refresh:\n                self.py3_wrapper.refresh_modules(module_name)\n                default_event = False\n\n        if default_event:\n            # default button 2 action is to clear this method's cache\n            if self.config[\"debug\"]:\n                self.py3_wrapper.log(f\"dispatching default event {event}\")\n            self.py3_wrapper.refresh_modules(module_name)\n\n        # find container that holds the module and call its onclick\n        module_groups = self.py3_config[\".module_groups\"]\n        containers = module_groups.get(module_name, [])\n        for container in containers:\n            self.process_event(container, event)\n\n    def dispatch_event(self, event):\n        \"\"\"\n        Takes an event dict.  Logs the event if needed and cleans up the dict\n        such as setting the index needed for composits.\n        \"\"\"\n        if self.config[\"debug\"]:\n            self.py3_wrapper.log(f\"received event {event}\")\n\n        # usage variables\n        event[\"index\"] = event.get(\"index\", \"\")\n        instance = event.get(\"instance\", \"\")\n        name = event.get(\"name\", \"\")\n\n        # composites have an index which is passed to i3bar with\n        # the instance.  We need to separate this out here and\n        # clean up the event.  If index\n        # is an integer type then cast it as such.\n        if \" \" in instance:\n            instance, index = instance.split(\" \", 1)\n            try:\n                index = int(index)\n            except ValueError:\n                pass\n            event[\"index\"] = index\n            event[\"instance\"] = instance\n\n        if self.config[\"debug\"]:\n            self.py3_wrapper.log(\n                'trying to dispatch event to module \"{}\"'.format(\n                    f\"{name} {instance}\".strip()\n                )\n            )\n\n        # guess the module config name\n        module_name = f\"{name} {instance}\".strip()\n\n        default_event = False\n        module_info = self.output_modules.get(module_name)\n        module = module_info[\"module\"]\n        # execute any configured i3-msg command\n        # we do not do this for containers\n        # modules that have failed do not execute their config on_click\n        if module.allow_config_clicks:\n            button = event.get(\"button\", 0)\n            on_click = self.on_click.get(module_name, {}).get(str(button))\n            if on_click:\n                task = EventClickTask(module_name, event, self, on_click)\n                self.py3_wrapper.timeout_queue_add(task)\n            # otherwise setup default action on button 2 press\n            elif button == 2:\n                default_event = True\n\n        # do the work\n        task = EventTask(module_name, event, default_event, self)\n        self.py3_wrapper.timeout_queue_add(task)\n\n    @profile\n    def run(self):\n        \"\"\"\n        Wait for an i3bar JSON event, then find the right module to dispatch\n        the message to based on the 'name' and 'instance' of the event.\n\n        In case the module does NOT support click_events, the default\n        implementation is to clear the module's cache\n        when the MIDDLE button (2) is pressed on it.\n\n        Example event:\n        {'y': 13, 'x': 1737, 'button': 1, 'name': 'empty', 'instance': 'first'}\n        \"\"\"\n        try:\n            while self.py3_wrapper.running:\n                event_str = self.poller_inp.readline()\n                if not event_str:\n                    continue\n                try:\n                    # remove leading comma if present\n                    if event_str[0] == \",\":\n                        event_str = event_str[1:]\n                    event = loads(event_str)\n                    self.dispatch_event(event)\n                except Exception:\n                    self.py3_wrapper.report_exception(\"Event failed\")\n        except:  # noqa e722\n            err = \"Events thread died, click events are disabled.\"\n            self.py3_wrapper.report_exception(err, notify_user=False)\n            self.py3_wrapper.notify_user(err, level=\"warning\")\n", "path": "py3status/events.py"}]}