py3status: Battery module error

Describe the bug The bug seems to ocurr when my battery is fully charged and I’m using the acpi measurement mode (I’d wish to be able to use acpi measuring to get the time that the battery has) Your py3status version py3status version 3.49 (python 3.10.9) on sway

To Reproduce Steps to reproduce the behavior along with your py3status configuration (filter out any private values):

  1. Add module ‘battery_level’
  2. Configure module like the following:
battery_level {
    blocks = ""
    #battery_id = all
    battery_id = 1 
    format = "{percent}% {icon}[\?if=time_remainin>
    threshold_degraded = 20
    hide_when_full = true
    hide_seconds = true
    notify_low_level = true
    #measurement_mode = "sys"
    measurement_mode = "acpi"
    notification = true
}
  1. Wait until the battery is at 100% and the error sometimes pops up.
  2. See error.

Expected behavior The battery level to continue being hidden and no error to pop up.

Additional context The error says battery_level: list index out of range, which I presume means some error with the acpi handling? The logs say the following:

2023-03-25 10:26:23 WARNING Instance `battery_level`, user method `battery_level` failed.
2023-03-25 10:26:23 INFO Traceback
IndexError: list index out of range
  File "/usr/lib/python3.10/site-packages/py3status/module.py", line 949, in run 
    response = method()
  File "/usr/lib/python3.10/site-packages/py3status/modules/battery_level.py", line 198, in battery_level
    battery_list = self.get_battery_info()
  File "/usr/lib/python3.10/site-packages/py3status/modules/battery_level.py", line 290, in _extract_battery_info_from_acpi
    return [_parse_battery_info(battery) for battery in acpi_list]
  File "/usr/lib/python3.10/site-packages/py3status/modules/battery_level.py", line 290, in <listcomp>
    return [_parse_battery_info(battery) for battery in acpi_list]
  File "/usr/lib/python3.10/site-packages/py3status/modules/battery_level.py", line 262, in _parse_battery_info
    findall(r"(?<= )(\d+)(?= mAh)", acpi_battery_lines[1])[1]

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 21 (9 by maintainers)

Most upvoted comments

diff --git a/py3status/modules/battery_level.py b/py3status/modules/battery_level.py
index 2a48b83..046e30f 100644
--- a/py3status/modules/battery_level.py
+++ b/py3status/modules/battery_level.py
@@ -92,7 +92,7 @@ discharging
 {'color': '#FF0000', 'full_text': u'\u2340'}
 """
 
-from re import findall
+from re import findall, search
 
 import itertools
 import math
@@ -178,6 +178,7 @@ class Py3status:
 
     def post_config_hook(self):
         self.last_known_status = ""
+        self.last_known_capacity = 1
         # Guess mode if not set
         if self.measurement_mode is None:
             if Path(self.sys_battery_path).is_dir():
@@ -258,13 +259,14 @@ class Py3status:
                 findall(r"(?<= )(\d+)(?=%)", acpi_battery_lines[0])[0]
             )
             battery["charging"] = "Charging" in acpi_battery_lines[0]
-            battery["capacity"] = int(
-                findall(r"(?<= )(\d+)(?= mAh)", acpi_battery_lines[1])[1]
-            )
 
             # ACPI only shows time remaining if battery is discharging or
             # charging
             try:
+                battery["capacity"] = int(
+                    findall(r"(?<= )(\d+)(?= mAh)", acpi_battery_lines[1])[1]
+                )
+                self.last_known_capacity = battery["capacity"]
                 battery["time_remaining"] = "".join(
                     findall(
                         r"(?<=, )(\d+:\d+:\d+)(?= remaining)|"
@@ -273,6 +275,7 @@ class Py3status:
                     )[0]
                 )
             except IndexError:
+                battery["capacity"] = self.last_known_capacity
                 battery["time_remaining"] = FULLY_CHARGED
 
             # TODO: Not implemented yet
@@ -285,9 +288,17 @@ class Py3status:
         # Separate the output because each pair of lines corresponds to a
         # single battery.  Now the list index will correspond to the index of
         # the battery we want to look at
-        acpi_list = [acpi_list[i : i + 2] for i in range(0, len(acpi_list) - 1, 2)]
+        temp_acpi_list = {}
+        for line in acpi_list:
+            number = search(r"Battery (\d+)", line).group(1)
+            temp_acpi_list.setdefault(number, []).append(line)
+
+        new_acpi_list = {}
+        for k, v in temp_acpi_list.items():
+            if "rate information unavailable" not in "|".join(v):
+                new_acpi_list[k] = v
 
-        return [_parse_battery_info(battery) for battery in acpi_list]
+        return [_parse_battery_info(battery) for battery in new_acpi_list.values()]
 
     def _extract_battery_info_from_sys(self):
         """