Repository: ultrabug/py3status

Issue:
sysdata divison by zero error
```
2017-01-17 12:51:07 INFO method sysData returned {'composite': [{'full_text': 'CPU: 12.42%', 'color': '#00FF00', 'instance': ' 0', 'name': 'sysdata', 'separator': False, 'separator_block_width': 0}, {'full_text': ', ', 'instance': ' 1', 'name': 'sysdata', 'separator': False, 'separator_block_width': 0}, {'full_text': 'Mem: 2.25/7.73 GB (29.06%)', 'color': '#00FF00', 'instance': ' 2', 'name': 'sysdata'}], 'instance': '', 'name': 'sysdata'} 
2017-01-17 12:51:07 WARNING Instance `sysdata`, user method `sysData` failed (ZeroDivisionError) sysdata.py line 261.
2017-01-17 12:51:08 INFO Traceback
ZeroDivisionError: float division by zero
  File "/home/chris/src/py3status/py3status/module.py", line 584, in run
    response = method()
  File "/home/chris/src/py3status/py3status/modules/sysdata.py", line 261, in sysData
    float(cpu_idle-self.cpu_idle) / float(cpu_total-self.cpu_total)

2017-01-17 12:51:08 ERROR py3status: Instance `sysdata`, user method `sysData` failed (ZeroDivisionError) sysdata.py line 261. Please try to fix this and reload i3wm (Mod+Shift+R)
```


Discussion:
Not easily reproducible. This was on the screen when I came back. It may be related to computer idling/sleeping/suspending/waking. I was away for an hour.
I also usually get a `ZeroDivisionError` when my battery is almost dead ... I'll see if I can reproduce and post the logs.
I started tracking this down months ago but never figured it out. When the exception appears my status bar stops updating.  It was happening to me after the screen had been locked and I found I was able to occasionally trigger it by locking and waiting 15-30 seconds then unlocking.  I added some verbosity to the module and I can see after unlocking that sometimes the process takes ~10 seconds to get moving again and usually in these cases there is no ZeroDivisionError exception. When that error does appear it was because cpu_total == self.cpu_total.  I found I could prevent the exception by setting both self.cpu_total and self.cpu_idle to 0 in that condition before letting the script calculate and set cpu_usage.  In my logs I also noticed multiple instances of the same class ran at the same time. I added a few lines to write the value of "self" to a file noting which class it was.  


Although reproducing may be difficult the issue is when `cpu_total - self.cpu_total` is zero.  So we should either explicitly test for this or just wrap the calculation in a try/except.

What the value should be then is the only question.  As This is a rare condition and really means that nothing has been done then any value would be fine but I'd just go with `0`



Resolving patch:
diff --git a/py3status/modules/sysdata.py b/py3status/modules/sysdata.py
--- a/py3status/modules/sysdata.py
+++ b/py3status/modules/sysdata.py
@@ -291,9 +291,11 @@ def sysData(self):
         # get CPU usage info
         if self.py3.format_contains(self.format, 'cpu_usage'):
             cpu_total, cpu_idle = self.data.cpu()
-            cpu_usage = (1 - (
-                float(cpu_idle - self.cpu_idle) / float(cpu_total - self.cpu_total)
-            )) * 100
+            cpu_usage = 0
+            if cpu_total != self.cpu_total:
+                cpu_usage = (1 - (
+                    float(cpu_idle - self.cpu_idle) / float(cpu_total - self.cpu_total)
+                )) * 100
             self.values['cpu_usage'] = cpu_usage
             self.cpu_total = cpu_total
             self.cpu_idle = cpu_idle


Test patch: