Repository: ultrabug/py3status

Issue:
Treat None as a zero when using conditions 
We can get this in `thunderbird_todos` where `priority` will be `None` if it's not used. Otherwise, it will be a number over `0`. Different number for `Low`, `Normal`, `High` too.
```
# display incompleted tasks with any priority
thunderbird_todos {
    format_todo = '\?if=!todo_completed [\?if=priority>0 {title}]'
    format_separator = ' '
}
```
I ran into this issue with `input` module too many moons ago.
```
format = '\?if=scroll_dy<0 down|up'    # scroll_dy is None
```
```
2017-09-30 03:39:03 WARNING Invalid format `[\?if=scroll_dy<0 down|up]` (TypeError) keyboard_locks.py line 293.
2017-09-30 03:39:03 INFO Traceback
TypeError: '<' not supported between instances of 'NoneType' and 'str'
  File "/home/chris/src/py3status/py3status/modules/keyboard_locks.py", line 293, in keyboard_mouse
    'full_text': self.py3.safe_format(self.format, self.x)
  File "/home/chris/src/py3status/py3status/py3.py", line 742, in safe_format
    attr_getter=attr_getter,
  File "/home/chris/src/py3status/py3status/formatter.py", line 213, in format
    valid, output = first_block.render(get_parameter, module)
  File "/home/chris/src/py3status/py3status/formatter.py", line 533, in render
    sub_valid, sub_output = item.render(get_params, module)
  File "/home/chris/src/py3status/py3status/formatter.py", line 522, in render
    valid = self.check_valid(get_params)
  File "/home/chris/src/py3status/py3status/formatter.py", line 505, in check_valid
    return self.commands._if.check_valid(get_params)
  File "/home/chris/src/py3status/py3status/formatter.py", line 367, in _check_valid_condition
    return (variable < value) == self.default
```


Discussion:
```
>>> 0 == None
False
>>> 0 < None
False
>>> 0 > None
True
>>> 
```

but yes we shouldn't break if we can help it
This trips on nonexistent keys too.
```
diff --git a/py3status/modules/static_string.py b/py3status/modules/static_string.py
index dbcec8c6..5a589cba 100644
--- a/py3status/modules/static_string.py
+++ b/py3status/modules/static_string.py
@@ -16,7 +16,7 @@ class Py3status:
     """
     """
     # available configuration parameters
-    format = 'Hello, world!'
+    format = '\?if=nonexistent_key>0 {tobes}'
 
     def static_string(self):
         return {
```
```
Invalid format `\?if=nonexistent_key>0 {tobes}` (TypeError) static_string.py line 24.
Traceback
TypeError: unorderable types: NoneType() > str()
  File "static_string.py", line 24, in static_string
    'full_text': self.py3.safe_format(self.format),
  File "/home/chris/src/py3status/py3status/py3.py", line 750, in safe_format
    attr_getter=attr_getter,
  File "/home/chris/src/py3status/py3status/formatter.py", line 213, in format
    valid, output = first_block.render(get_parameter, module)
  File "/home/chris/src/py3status/py3status/formatter.py", line 522, in render
    valid = self.check_valid(get_params)
  File "/home/chris/src/py3status/py3status/formatter.py", line 505, in check_valid
    return self.commands._if.check_valid(get_params)
  File "/home/chris/src/py3status/py3status/formatter.py", line 365, in _check_valid_condition
    return (variable > value) == self.default

{'cached_until': -1, 'full_text': 'invalid format'}
```

Resolving patch:
diff --git a/py3status/formatter.py b/py3status/formatter.py
--- a/py3status/formatter.py
+++ b/py3status/formatter.py
@@ -349,6 +349,10 @@ def _check_valid_condition(self, get_params):
             variable = None
         value = self.value
 
+        # if None, return oppositely
+        if variable is None:
+            return not self.default
+
         # convert the value to a correct type
         if isinstance(variable, bool):
             value = bool(self.value)


Test patch:
diff --git a/tests/test_formatter.py b/tests/test_formatter.py
--- a/tests/test_formatter.py
+++ b/tests/test_formatter.py
@@ -1338,6 +1338,20 @@ def test_conditions_21():
     })
 
 
+def test_conditions_22():
+    run_formatter({
+        'format': '\?if=missing>John cool beans',
+        'expected': ''
+    })
+
+
+def test_conditions_23():
+    run_formatter({
+        'format': '[\?if=None=None cool] beans',
+        'expected': ' beans'
+    })
+
+
 if __name__ == '__main__':
     # run tests
     import sys