We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
group cycle/click events fail
Since happy-endings we get an AttributeError L154 of events.py

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

{"golden_diff": "diff --git a/py3status/events.py b/py3status/events.py\n--- a/py3status/events.py\n+++ b/py3status/events.py\n@@ -148,10 +148,15 @@\n             return\n         module = module_info['module']\n \n+        try:\n+            errors = module.error_messages\n+        except AttributeError:\n+            errors = False\n+\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 top_level and not module.error_messages:\n+        if top_level and not errors:\n             click_module = event['name']\n             if event['instance']:\n                 click_module += ' ' + event['instance']\n", "issue": "group cycle/click events fail\nSince happy-endings we get an AttributeError L154 of events.py\n", "before_files": [{"content": "import select\nimport sys\n\nfrom threading import Thread\nfrom subprocess import Popen, PIPE\nfrom json import loads\n\nfrom py3status.profiling import profile\n\ntry:\n    # Python 3\n    from shlex import quote as shell_quote\nexcept ImportError:\n    # Python 2\n    from pipes import quote as shell_quote\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 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.lock = py3_wrapper.lock\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        if module_info:\n            output = module_info['module'].get_latest()\n            full_text = u''.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,\n                                                               event)\n                command = command.replace('$OUTPUT_PART',\n                                          shell_quote(partial_text))\n                command = command.replace('$OUTPUT', shell_quote(full_text))\n\n            # this is a i3 message\n            self.i3_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 i3_msg(self, module_name, command):\n        \"\"\"\n        Execute the given i3 message and log its output.\n        \"\"\"\n        i3_msg_pipe = Popen(['i3-msg', command], stdout=PIPE)\n        self.py3_wrapper.log('i3-msg module=\"{}\" command=\"{}\" stdout={}'.format(\n            module_name, command, i3_msg_pipe.stdout.read()))\n\n    def process_event(self, module_name, event, top_level=True):\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        button = event.get('button', 0)\n        default_event = False\n\n        # get the module that the event is for\n        module_info = self.output_modules.get(module_name)\n        if not module_info:\n            return\n        module = module_info['module']\n\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 top_level and not module.error_messages:\n            click_module = event['name']\n            if event['instance']:\n                click_module += ' ' + event['instance']\n            btn = str(button)\n            if self.on_click.get(click_module, {}).get(btn):\n                self.on_click_dispatcher(click_module,\n                                         event,\n                                         self.on_click[module_name].get(btn))\n            # otherwise setup default action on button 2 press\n            elif button == 2:\n                default_event = True\n\n        # if module is a py3status one call it.\n        if module_info['type'] == 'py3status':\n            module.click_event(event)\n            if self.config['debug']:\n                self.py3_wrapper.log('dispatching event {}'.format(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(\n                    'dispatching default event {}'.format(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, top_level=False)\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('received event {}'.format(event))\n        # usage variables\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                    '{} {}'.format(name, instance).strip()))\n\n        # guess the module config name\n        module_name = '{} {}'.format(name, instance).strip()\n        # do the work\n        self.process_event(module_name, event)\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        while self.lock.is_set():\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", "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\n\nfrom py3status.profiling import profile\n\ntry:\n    # Python 3\n    from shlex import quote as shell_quote\nexcept ImportError:\n    # Python 2\n    from pipes import quote as shell_quote\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 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.lock = py3_wrapper.lock\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        if module_info:\n            output = module_info['module'].get_latest()\n            full_text = u''.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,\n                                                               event)\n                command = command.replace('$OUTPUT_PART',\n                                          shell_quote(partial_text))\n                command = command.replace('$OUTPUT', shell_quote(full_text))\n\n            # this is a i3 message\n            self.i3_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 i3_msg(self, module_name, command):\n        \"\"\"\n        Execute the given i3 message and log its output.\n        \"\"\"\n        i3_msg_pipe = Popen(['i3-msg', command], stdout=PIPE)\n        self.py3_wrapper.log('i3-msg module=\"{}\" command=\"{}\" stdout={}'.format(\n            module_name, command, i3_msg_pipe.stdout.read()))\n\n    def process_event(self, module_name, event, top_level=True):\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        button = event.get('button', 0)\n        default_event = False\n\n        # get the module that the event is for\n        module_info = self.output_modules.get(module_name)\n        if not module_info:\n            return\n        module = module_info['module']\n\n        try:\n            errors = module.error_messages\n        except AttributeError:\n            errors = False\n\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 top_level and not errors:\n            click_module = event['name']\n            if event['instance']:\n                click_module += ' ' + event['instance']\n            btn = str(button)\n            if self.on_click.get(click_module, {}).get(btn):\n                self.on_click_dispatcher(click_module,\n                                         event,\n                                         self.on_click[module_name].get(btn))\n            # otherwise setup default action on button 2 press\n            elif button == 2:\n                default_event = True\n\n        # if module is a py3status one call it.\n        if module_info['type'] == 'py3status':\n            module.click_event(event)\n            if self.config['debug']:\n                self.py3_wrapper.log('dispatching event {}'.format(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(\n                    'dispatching default event {}'.format(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, top_level=False)\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('received event {}'.format(event))\n        # usage variables\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                    '{} {}'.format(name, instance).strip()))\n\n        # guess the module config name\n        module_name = '{} {}'.format(name, instance).strip()\n        # do the work\n        self.process_event(module_name, event)\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        while self.lock.is_set():\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", "path": "py3status/events.py"}]}