We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
CPU usage leak
Running qtile master. Over a timespan of about 24 hours, qtile's CPU usage rises from trivially low to nearly 100%. In the worst stages, qtile is non-responsive to keyboard shortcuts, forcing me to kill it externally.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `libqtile/widget/battery.py`
Content:
```
1 import cairo
2 import os
3 from libqtile import bar
4 import base
5 
6 BAT_DIR = '/sys/class/power_supply'
7 CHARGED = 'Full'
8 CHARGING = 'Charging'
9 DISCHARGING = 'Discharging'
10 UNKNOWN = 'Unknown'
11 
12 BATTERY_INFO_FILES = {
13     'energy_now_file': ['energy_now', 'charge_now'],
14     'energy_full_file': ['energy_full', 'charge_full'],
15     'power_now_file': ['power_now', 'current_now'],
16     'status_file': ['status'],
17 }
18 
19 
20 def default_icon_path():
21     # default icons are in libqtile/resources/battery-icons
22     root = os.sep.join(os.path.abspath(__file__).split(os.sep)[:-2])
23     return os.path.join(root, 'resources', 'battery-icons')
24 
25 
26 class _Battery(base._TextBox):
27     ''' Base battery class '''
28 
29     filenames = {}
30 
31     defaults = [
32         ('battery_name', 'BAT0', 'ACPI name of a battery, usually BAT0'),
33         (
34             'status_file',
35             'status',
36             'Name of status file in'
37             ' /sys/class/power_supply/battery_name'
38         ),
39         (
40             'energy_now_file',
41             None,
42             'Name of file with the '
43             'current energy in /sys/class/power_supply/battery_name'
44         ),
45         (
46             'energy_full_file',
47             None,
48             'Name of file with the maximum'
49             ' energy in /sys/class/power_supply/battery_name'
50         ),
51         (
52             'power_now_file',
53             None,
54             'Name of file with the current'
55             ' power draw in /sys/class/power_supply/battery_name'
56         ),
57         ('update_delay', 1, 'The delay in seconds between updates'),
58     ]
59 
60     def __init__(self, **config):
61         base._TextBox.__init__(self, "BAT", bar.CALCULATED, **config)
62         self.add_defaults(_Battery.defaults)
63 
64     def _load_file(self, name):
65         try:
66             path = os.path.join(BAT_DIR, self.battery_name, name)
67             with open(path, 'r') as f:
68                 return f.read().strip()
69         except IOError:
70             if name == 'current_now':
71                 return 0
72             return False
73         except Exception:
74             self.log.exception("Failed to get %s" % name)
75 
76     def _get_param(self, name):
77         if name in self.filenames:
78             return self._load_file(self.filenames[name])
79         else:
80             # Don't have the file name cached, figure it out
81             file_list = BATTERY_INFO_FILES.get(name, [])
82             if getattr(self, name, None):
83                 # If a file is manually specified, check it first
84                 file_list.insert(0, getattr(self, name))
85 
86             # Iterate over the possibilities, and return the first valid value
87             for file in file_list:
88                 value = self._load_file(file)
89                 if not (value in (False, None)):
90                     self.filenames[name] = file
91                     return value
92 
93         # If we made it this far, we don't have a valid file. Just return None.
94         return None
95 
96     def _get_info(self):
97         try:
98             info = {
99                 'stat': self._get_param('status_file'),
100                 'now': float(self._get_param('energy_now_file')),
101                 'full': float(self._get_param('energy_full_file')),
102                 'power': float(self._get_param('power_now_file')),
103             }
104         except TypeError:
105             return False
106         return info
107 
108 
109 class Battery(_Battery):
110     """
111         A simple but flexible text-based battery widget.
112     """
113     defaults = [
114         ('low_foreground', 'FF0000', 'font color when battery is low'),
115         (
116             'format',
117             '{char} {percent:2.0%} {hour:d}:{min:02d}',
118             'Display format'
119         ),
120         ('charge_char', '^', 'Character to indicate the battery is charging'),
121         (
122             'discharge_char',
123             'V',
124             'Character to indicate the battery'
125             ' is discharging'
126         ),
127         (
128             'low_percentage',
129             0.10,
130             "0 < x < 1 at which to indicate battery is low with low_foreground"
131         ),
132         ('hide_threshold', None, 'Hide the text when there is enough energy'),
133     ]
134 
135     def __init__(self, **config):
136         _Battery.__init__(self, **config)
137         self.add_defaults(Battery.defaults)
138         self.timeout_add(self.update_delay, self.update)
139         self.update()
140 
141     def _get_text(self):
142         info = self._get_info()
143         if info is False:
144             return 'Error'
145 
146         # Set the charging character
147         try:
148             # hide the text when it's higher than threshold, but still
149             # display `full` when the battery is fully charged.
150             if self.hide_threshold and \
151                     info['now'] / info['full'] * 100.0 >= \
152                     self.hide_threshold and \
153                     info['stat'] != CHARGED:
154                 return ''
155             elif info['stat'] == DISCHARGING:
156                 char = self.discharge_char
157                 time = info['now'] / info['power']
158             elif info['stat'] == CHARGING:
159                 char = self.charge_char
160                 time = (info['full'] - info['now']) / info['power']
161             else:
162                 return 'Full'
163         except ZeroDivisionError:
164             time = -1
165 
166         # Calculate the battery percentage and time left
167         if time >= 0:
168             hour = int(time)
169             min = int(time * 60) % 60
170         else:
171             hour = -1
172             min = -1
173         percent = info['now'] / info['full']
174         if info['stat'] == DISCHARGING and percent < self.low_percentage:
175             self.layout.colour = self.low_foreground
176         else:
177             self.layout.colour = self.foreground
178 
179         return self.format.format(
180             char=char,
181             percent=percent,
182             hour=hour,
183             min=min
184         )
185 
186     def update(self):
187         if self.configured:
188             ntext = self._get_text()
189             if ntext != self.text:
190                 self.text = ntext
191                 self.bar.draw()
192         return True
193 
194 
195 class BatteryIcon(_Battery):
196     ''' Battery life indicator widget '''
197 
198     defaults = [
199         ('theme_path', default_icon_path(), 'Path of the icons'),
200         ('custom_icons', {}, 'dict containing key->filename icon map'),
201     ]
202 
203     def __init__(self, **config):
204         _Battery.__init__(self, **config)
205         self.add_defaults(BatteryIcon.defaults)
206 
207         if self.theme_path:
208             self.width_type = bar.STATIC
209             self.width = 0
210         self.surfaces = {}
211         self.current_icon = 'battery-missing'
212         self.icons = dict([(x, '{0}.png'.format(x)) for x in (
213             'battery-missing',
214             'battery-caution',
215             'battery-low',
216             'battery-good',
217             'battery-full',
218             'battery-caution-charging',
219             'battery-low-charging',
220             'battery-good-charging',
221             'battery-full-charging',
222             'battery-full-charged',
223         )])
224         self.icons.update(self.custom_icons)
225         self.timeout_add(self.update_delay, self.update)
226 
227     def _configure(self, qtile, bar):
228         base._TextBox._configure(self, qtile, bar)
229         self.setup_images()
230 
231     def _get_icon_key(self):
232         key = 'battery'
233         info = self._get_info()
234         if info is False or not info.get('full'):
235             key += '-missing'
236         else:
237             percent = info['now'] / info['full']
238             if percent < .2:
239                 key += '-caution'
240             elif percent < .4:
241                 key += '-low'
242             elif percent < .8:
243                 key += '-good'
244             else:
245                 key += '-full'
246 
247             if info['stat'] == CHARGING:
248                 key += '-charging'
249             elif info['stat'] == CHARGED:
250                 key += '-charged'
251         return key
252 
253     def update(self):
254         if self.configured:
255             icon = self._get_icon_key()
256             if icon != self.current_icon:
257                 self.current_icon = icon
258                 self.draw()
259         return True
260 
261     def draw(self):
262         if self.theme_path:
263             self.drawer.clear(self.background or self.bar.background)
264             self.drawer.ctx.set_source(self.surfaces[self.current_icon])
265             self.drawer.ctx.paint()
266             self.drawer.draw(self.offset, self.width)
267         else:
268             self.text = self.current_icon[8:]
269             base._TextBox.draw(self)
270 
271     def setup_images(self):
272         for key, name in self.icons.iteritems():
273             try:
274                 path = os.path.join(self.theme_path, name)
275                 img = cairo.ImageSurface.create_from_png(path)
276             except cairo.Error:
277                 self.theme_path = None
278                 self.qtile.log.warning('Battery Icon switching to text mode')
279                 return
280             input_width = img.get_width()
281             input_height = img.get_height()
282 
283             sp = input_height / float(self.bar.height - 1)
284 
285             width = input_width / sp
286             if width > self.width:
287                 self.width = int(width) + self.actual_padding * 2
288 
289             imgpat = cairo.SurfacePattern(img)
290 
291             scaler = cairo.Matrix()
292 
293             scaler.scale(sp, sp)
294             scaler.translate(self.actual_padding * -1, 0)
295             imgpat.set_matrix(scaler)
296 
297             imgpat.set_filter(cairo.FILTER_BEST)
298             self.surfaces[key] = imgpat
299
```
--- 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/libqtile/widget/battery.py b/libqtile/widget/battery.py
--- a/libqtile/widget/battery.py
+++ b/libqtile/widget/battery.py
@@ -74,11 +74,14 @@
             self.log.exception("Failed to get %s" % name)
 
     def _get_param(self, name):
-        if name in self.filenames:
+        if name in self.filenames and self.filenames[name]:
             return self._load_file(self.filenames[name])
-        else:
+        elif name not in self.filenames:
             # Don't have the file name cached, figure it out
-            file_list = BATTERY_INFO_FILES.get(name, [])
+
+            # Don't modify the global list! Copy with [:]
+            file_list = BATTERY_INFO_FILES.get(name, [])[:]
+
             if getattr(self, name, None):
                 # If a file is manually specified, check it first
                 file_list.insert(0, getattr(self, name))
@@ -90,7 +93,10 @@
                     self.filenames[name] = file
                     return value
 
-        # If we made it this far, we don't have a valid file. Just return None.
+        # If we made it this far, we don't have a valid file.
+        # Set it to None to avoid trying the next time.
+        self.filenames[name] = None
+
         return None
 
     def _get_info(self):

{"golden_diff": "diff --git a/libqtile/widget/battery.py b/libqtile/widget/battery.py\n--- a/libqtile/widget/battery.py\n+++ b/libqtile/widget/battery.py\n@@ -74,11 +74,14 @@\n             self.log.exception(\"Failed to get %s\" % name)\n \n     def _get_param(self, name):\n-        if name in self.filenames:\n+        if name in self.filenames and self.filenames[name]:\n             return self._load_file(self.filenames[name])\n-        else:\n+        elif name not in self.filenames:\n             # Don't have the file name cached, figure it out\n-            file_list = BATTERY_INFO_FILES.get(name, [])\n+\n+            # Don't modify the global list! Copy with [:]\n+            file_list = BATTERY_INFO_FILES.get(name, [])[:]\n+\n             if getattr(self, name, None):\n                 # If a file is manually specified, check it first\n                 file_list.insert(0, getattr(self, name))\n@@ -90,7 +93,10 @@\n                     self.filenames[name] = file\n                     return value\n \n-        # If we made it this far, we don't have a valid file. Just return None.\n+        # If we made it this far, we don't have a valid file.\n+        # Set it to None to avoid trying the next time.\n+        self.filenames[name] = None\n+\n         return None\n \n     def _get_info(self):\n", "issue": "CPU usage leak\nRunning qtile master. Over a timespan of about 24 hours, qtile's CPU usage rises from trivially low to nearly 100%. In the worst stages, qtile is non-responsive to keyboard shortcuts, forcing me to kill it externally.\n\n", "before_files": [{"content": "import cairo\nimport os\nfrom libqtile import bar\nimport base\n\nBAT_DIR = '/sys/class/power_supply'\nCHARGED = 'Full'\nCHARGING = 'Charging'\nDISCHARGING = 'Discharging'\nUNKNOWN = 'Unknown'\n\nBATTERY_INFO_FILES = {\n    'energy_now_file': ['energy_now', 'charge_now'],\n    'energy_full_file': ['energy_full', 'charge_full'],\n    'power_now_file': ['power_now', 'current_now'],\n    'status_file': ['status'],\n}\n\n\ndef default_icon_path():\n    # default icons are in libqtile/resources/battery-icons\n    root = os.sep.join(os.path.abspath(__file__).split(os.sep)[:-2])\n    return os.path.join(root, 'resources', 'battery-icons')\n\n\nclass _Battery(base._TextBox):\n    ''' Base battery class '''\n\n    filenames = {}\n\n    defaults = [\n        ('battery_name', 'BAT0', 'ACPI name of a battery, usually BAT0'),\n        (\n            'status_file',\n            'status',\n            'Name of status file in'\n            ' /sys/class/power_supply/battery_name'\n        ),\n        (\n            'energy_now_file',\n            None,\n            'Name of file with the '\n            'current energy in /sys/class/power_supply/battery_name'\n        ),\n        (\n            'energy_full_file',\n            None,\n            'Name of file with the maximum'\n            ' energy in /sys/class/power_supply/battery_name'\n        ),\n        (\n            'power_now_file',\n            None,\n            'Name of file with the current'\n            ' power draw in /sys/class/power_supply/battery_name'\n        ),\n        ('update_delay', 1, 'The delay in seconds between updates'),\n    ]\n\n    def __init__(self, **config):\n        base._TextBox.__init__(self, \"BAT\", bar.CALCULATED, **config)\n        self.add_defaults(_Battery.defaults)\n\n    def _load_file(self, name):\n        try:\n            path = os.path.join(BAT_DIR, self.battery_name, name)\n            with open(path, 'r') as f:\n                return f.read().strip()\n        except IOError:\n            if name == 'current_now':\n                return 0\n            return False\n        except Exception:\n            self.log.exception(\"Failed to get %s\" % name)\n\n    def _get_param(self, name):\n        if name in self.filenames:\n            return self._load_file(self.filenames[name])\n        else:\n            # Don't have the file name cached, figure it out\n            file_list = BATTERY_INFO_FILES.get(name, [])\n            if getattr(self, name, None):\n                # If a file is manually specified, check it first\n                file_list.insert(0, getattr(self, name))\n\n            # Iterate over the possibilities, and return the first valid value\n            for file in file_list:\n                value = self._load_file(file)\n                if not (value in (False, None)):\n                    self.filenames[name] = file\n                    return value\n\n        # If we made it this far, we don't have a valid file. Just return None.\n        return None\n\n    def _get_info(self):\n        try:\n            info = {\n                'stat': self._get_param('status_file'),\n                'now': float(self._get_param('energy_now_file')),\n                'full': float(self._get_param('energy_full_file')),\n                'power': float(self._get_param('power_now_file')),\n            }\n        except TypeError:\n            return False\n        return info\n\n\nclass Battery(_Battery):\n    \"\"\"\n        A simple but flexible text-based battery widget.\n    \"\"\"\n    defaults = [\n        ('low_foreground', 'FF0000', 'font color when battery is low'),\n        (\n            'format',\n            '{char} {percent:2.0%} {hour:d}:{min:02d}',\n            'Display format'\n        ),\n        ('charge_char', '^', 'Character to indicate the battery is charging'),\n        (\n            'discharge_char',\n            'V',\n            'Character to indicate the battery'\n            ' is discharging'\n        ),\n        (\n            'low_percentage',\n            0.10,\n            \"0 < x < 1 at which to indicate battery is low with low_foreground\"\n        ),\n        ('hide_threshold', None, 'Hide the text when there is enough energy'),\n    ]\n\n    def __init__(self, **config):\n        _Battery.__init__(self, **config)\n        self.add_defaults(Battery.defaults)\n        self.timeout_add(self.update_delay, self.update)\n        self.update()\n\n    def _get_text(self):\n        info = self._get_info()\n        if info is False:\n            return 'Error'\n\n        # Set the charging character\n        try:\n            # hide the text when it's higher than threshold, but still\n            # display `full` when the battery is fully charged.\n            if self.hide_threshold and \\\n                    info['now'] / info['full'] * 100.0 >= \\\n                    self.hide_threshold and \\\n                    info['stat'] != CHARGED:\n                return ''\n            elif info['stat'] == DISCHARGING:\n                char = self.discharge_char\n                time = info['now'] / info['power']\n            elif info['stat'] == CHARGING:\n                char = self.charge_char\n                time = (info['full'] - info['now']) / info['power']\n            else:\n                return 'Full'\n        except ZeroDivisionError:\n            time = -1\n\n        # Calculate the battery percentage and time left\n        if time >= 0:\n            hour = int(time)\n            min = int(time * 60) % 60\n        else:\n            hour = -1\n            min = -1\n        percent = info['now'] / info['full']\n        if info['stat'] == DISCHARGING and percent < self.low_percentage:\n            self.layout.colour = self.low_foreground\n        else:\n            self.layout.colour = self.foreground\n\n        return self.format.format(\n            char=char,\n            percent=percent,\n            hour=hour,\n            min=min\n        )\n\n    def update(self):\n        if self.configured:\n            ntext = self._get_text()\n            if ntext != self.text:\n                self.text = ntext\n                self.bar.draw()\n        return True\n\n\nclass BatteryIcon(_Battery):\n    ''' Battery life indicator widget '''\n\n    defaults = [\n        ('theme_path', default_icon_path(), 'Path of the icons'),\n        ('custom_icons', {}, 'dict containing key->filename icon map'),\n    ]\n\n    def __init__(self, **config):\n        _Battery.__init__(self, **config)\n        self.add_defaults(BatteryIcon.defaults)\n\n        if self.theme_path:\n            self.width_type = bar.STATIC\n            self.width = 0\n        self.surfaces = {}\n        self.current_icon = 'battery-missing'\n        self.icons = dict([(x, '{0}.png'.format(x)) for x in (\n            'battery-missing',\n            'battery-caution',\n            'battery-low',\n            'battery-good',\n            'battery-full',\n            'battery-caution-charging',\n            'battery-low-charging',\n            'battery-good-charging',\n            'battery-full-charging',\n            'battery-full-charged',\n        )])\n        self.icons.update(self.custom_icons)\n        self.timeout_add(self.update_delay, self.update)\n\n    def _configure(self, qtile, bar):\n        base._TextBox._configure(self, qtile, bar)\n        self.setup_images()\n\n    def _get_icon_key(self):\n        key = 'battery'\n        info = self._get_info()\n        if info is False or not info.get('full'):\n            key += '-missing'\n        else:\n            percent = info['now'] / info['full']\n            if percent < .2:\n                key += '-caution'\n            elif percent < .4:\n                key += '-low'\n            elif percent < .8:\n                key += '-good'\n            else:\n                key += '-full'\n\n            if info['stat'] == CHARGING:\n                key += '-charging'\n            elif info['stat'] == CHARGED:\n                key += '-charged'\n        return key\n\n    def update(self):\n        if self.configured:\n            icon = self._get_icon_key()\n            if icon != self.current_icon:\n                self.current_icon = icon\n                self.draw()\n        return True\n\n    def draw(self):\n        if self.theme_path:\n            self.drawer.clear(self.background or self.bar.background)\n            self.drawer.ctx.set_source(self.surfaces[self.current_icon])\n            self.drawer.ctx.paint()\n            self.drawer.draw(self.offset, self.width)\n        else:\n            self.text = self.current_icon[8:]\n            base._TextBox.draw(self)\n\n    def setup_images(self):\n        for key, name in self.icons.iteritems():\n            try:\n                path = os.path.join(self.theme_path, name)\n                img = cairo.ImageSurface.create_from_png(path)\n            except cairo.Error:\n                self.theme_path = None\n                self.qtile.log.warning('Battery Icon switching to text mode')\n                return\n            input_width = img.get_width()\n            input_height = img.get_height()\n\n            sp = input_height / float(self.bar.height - 1)\n\n            width = input_width / sp\n            if width > self.width:\n                self.width = int(width) + self.actual_padding * 2\n\n            imgpat = cairo.SurfacePattern(img)\n\n            scaler = cairo.Matrix()\n\n            scaler.scale(sp, sp)\n            scaler.translate(self.actual_padding * -1, 0)\n            imgpat.set_matrix(scaler)\n\n            imgpat.set_filter(cairo.FILTER_BEST)\n            self.surfaces[key] = imgpat\n", "path": "libqtile/widget/battery.py"}], "after_files": [{"content": "import cairo\nimport os\nfrom libqtile import bar\nimport base\n\nBAT_DIR = '/sys/class/power_supply'\nCHARGED = 'Full'\nCHARGING = 'Charging'\nDISCHARGING = 'Discharging'\nUNKNOWN = 'Unknown'\n\nBATTERY_INFO_FILES = {\n    'energy_now_file': ['energy_now', 'charge_now'],\n    'energy_full_file': ['energy_full', 'charge_full'],\n    'power_now_file': ['power_now', 'current_now'],\n    'status_file': ['status'],\n}\n\n\ndef default_icon_path():\n    # default icons are in libqtile/resources/battery-icons\n    root = os.sep.join(os.path.abspath(__file__).split(os.sep)[:-2])\n    return os.path.join(root, 'resources', 'battery-icons')\n\n\nclass _Battery(base._TextBox):\n    ''' Base battery class '''\n\n    filenames = {}\n\n    defaults = [\n        ('battery_name', 'BAT0', 'ACPI name of a battery, usually BAT0'),\n        (\n            'status_file',\n            'status',\n            'Name of status file in'\n            ' /sys/class/power_supply/battery_name'\n        ),\n        (\n            'energy_now_file',\n            None,\n            'Name of file with the '\n            'current energy in /sys/class/power_supply/battery_name'\n        ),\n        (\n            'energy_full_file',\n            None,\n            'Name of file with the maximum'\n            ' energy in /sys/class/power_supply/battery_name'\n        ),\n        (\n            'power_now_file',\n            None,\n            'Name of file with the current'\n            ' power draw in /sys/class/power_supply/battery_name'\n        ),\n        ('update_delay', 1, 'The delay in seconds between updates'),\n    ]\n\n    def __init__(self, **config):\n        base._TextBox.__init__(self, \"BAT\", bar.CALCULATED, **config)\n        self.add_defaults(_Battery.defaults)\n\n    def _load_file(self, name):\n        try:\n            path = os.path.join(BAT_DIR, self.battery_name, name)\n            with open(path, 'r') as f:\n                return f.read().strip()\n        except IOError:\n            if name == 'current_now':\n                return 0\n            return False\n        except Exception:\n            self.log.exception(\"Failed to get %s\" % name)\n\n    def _get_param(self, name):\n        if name in self.filenames and self.filenames[name]:\n            return self._load_file(self.filenames[name])\n        elif name not in self.filenames:\n            # Don't have the file name cached, figure it out\n\n            # Don't modify the global list! Copy with [:]\n            file_list = BATTERY_INFO_FILES.get(name, [])[:]\n\n            if getattr(self, name, None):\n                # If a file is manually specified, check it first\n                file_list.insert(0, getattr(self, name))\n\n            # Iterate over the possibilities, and return the first valid value\n            for file in file_list:\n                value = self._load_file(file)\n                if not (value in (False, None)):\n                    self.filenames[name] = file\n                    return value\n\n        # If we made it this far, we don't have a valid file.\n        # Set it to None to avoid trying the next time.\n        self.filenames[name] = None\n\n        return None\n\n    def _get_info(self):\n        try:\n            info = {\n                'stat': self._get_param('status_file'),\n                'now': float(self._get_param('energy_now_file')),\n                'full': float(self._get_param('energy_full_file')),\n                'power': float(self._get_param('power_now_file')),\n            }\n        except TypeError:\n            return False\n        return info\n\n\nclass Battery(_Battery):\n    \"\"\"\n        A simple but flexible text-based battery widget.\n    \"\"\"\n    defaults = [\n        ('low_foreground', 'FF0000', 'font color when battery is low'),\n        (\n            'format',\n            '{char} {percent:2.0%} {hour:d}:{min:02d}',\n            'Display format'\n        ),\n        ('charge_char', '^', 'Character to indicate the battery is charging'),\n        (\n            'discharge_char',\n            'V',\n            'Character to indicate the battery'\n            ' is discharging'\n        ),\n        (\n            'low_percentage',\n            0.10,\n            \"0 < x < 1 at which to indicate battery is low with low_foreground\"\n        ),\n        ('hide_threshold', None, 'Hide the text when there is enough energy'),\n    ]\n\n    def __init__(self, **config):\n        _Battery.__init__(self, **config)\n        self.add_defaults(Battery.defaults)\n        self.timeout_add(self.update_delay, self.update)\n        self.update()\n\n    def _get_text(self):\n        info = self._get_info()\n        if info is False:\n            return 'Error'\n\n        # Set the charging character\n        try:\n            # hide the text when it's higher than threshold, but still\n            # display `full` when the battery is fully charged.\n            if self.hide_threshold and \\\n                    info['now'] / info['full'] * 100.0 >= \\\n                    self.hide_threshold and \\\n                    info['stat'] != CHARGED:\n                return ''\n            elif info['stat'] == DISCHARGING:\n                char = self.discharge_char\n                time = info['now'] / info['power']\n            elif info['stat'] == CHARGING:\n                char = self.charge_char\n                time = (info['full'] - info['now']) / info['power']\n            else:\n                return 'Full'\n        except ZeroDivisionError:\n            time = -1\n\n        # Calculate the battery percentage and time left\n        if time >= 0:\n            hour = int(time)\n            min = int(time * 60) % 60\n        else:\n            hour = -1\n            min = -1\n        percent = info['now'] / info['full']\n        if info['stat'] == DISCHARGING and percent < self.low_percentage:\n            self.layout.colour = self.low_foreground\n        else:\n            self.layout.colour = self.foreground\n\n        return self.format.format(\n            char=char,\n            percent=percent,\n            hour=hour,\n            min=min\n        )\n\n    def update(self):\n        if self.configured:\n            ntext = self._get_text()\n            if ntext != self.text:\n                self.text = ntext\n                self.bar.draw()\n        return True\n\n\nclass BatteryIcon(_Battery):\n    ''' Battery life indicator widget '''\n\n    defaults = [\n        ('theme_path', default_icon_path(), 'Path of the icons'),\n        ('custom_icons', {}, 'dict containing key->filename icon map'),\n    ]\n\n    def __init__(self, **config):\n        _Battery.__init__(self, **config)\n        self.add_defaults(BatteryIcon.defaults)\n\n        if self.theme_path:\n            self.width_type = bar.STATIC\n            self.width = 0\n        self.surfaces = {}\n        self.current_icon = 'battery-missing'\n        self.icons = dict([(x, '{0}.png'.format(x)) for x in (\n            'battery-missing',\n            'battery-caution',\n            'battery-low',\n            'battery-good',\n            'battery-full',\n            'battery-caution-charging',\n            'battery-low-charging',\n            'battery-good-charging',\n            'battery-full-charging',\n            'battery-full-charged',\n        )])\n        self.icons.update(self.custom_icons)\n        self.timeout_add(self.update_delay, self.update)\n\n    def _configure(self, qtile, bar):\n        base._TextBox._configure(self, qtile, bar)\n        self.setup_images()\n\n    def _get_icon_key(self):\n        key = 'battery'\n        info = self._get_info()\n        if info is False or not info.get('full'):\n            key += '-missing'\n        else:\n            percent = info['now'] / info['full']\n            if percent < .2:\n                key += '-caution'\n            elif percent < .4:\n                key += '-low'\n            elif percent < .8:\n                key += '-good'\n            else:\n                key += '-full'\n\n            if info['stat'] == CHARGING:\n                key += '-charging'\n            elif info['stat'] == CHARGED:\n                key += '-charged'\n        return key\n\n    def update(self):\n        if self.configured:\n            icon = self._get_icon_key()\n            if icon != self.current_icon:\n                self.current_icon = icon\n                self.draw()\n        return True\n\n    def draw(self):\n        if self.theme_path:\n            self.drawer.clear(self.background or self.bar.background)\n            self.drawer.ctx.set_source(self.surfaces[self.current_icon])\n            self.drawer.ctx.paint()\n            self.drawer.draw(self.offset, self.width)\n        else:\n            self.text = self.current_icon[8:]\n            base._TextBox.draw(self)\n\n    def setup_images(self):\n        for key, name in self.icons.iteritems():\n            try:\n                path = os.path.join(self.theme_path, name)\n                img = cairo.ImageSurface.create_from_png(path)\n            except cairo.Error:\n                self.theme_path = None\n                self.qtile.log.warning('Battery Icon switching to text mode')\n                return\n            input_width = img.get_width()\n            input_height = img.get_height()\n\n            sp = input_height / float(self.bar.height - 1)\n\n            width = input_width / sp\n            if width > self.width:\n                self.width = int(width) + self.actual_padding * 2\n\n            imgpat = cairo.SurfacePattern(img)\n\n            scaler = cairo.Matrix()\n\n            scaler.scale(sp, sp)\n            scaler.translate(self.actual_padding * -1, 0)\n            imgpat.set_matrix(scaler)\n\n            imgpat.set_filter(cairo.FILTER_BEST)\n            self.surfaces[key] = imgpat\n", "path": "libqtile/widget/battery.py"}]}