Hello community,

here is the log from the commit of package python-py3status for 
openSUSE:Factory checked in at 2019-10-21 12:32:12
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-py3status (Old)
 and      /work/SRC/openSUSE:Factory/.python-py3status.new.2352 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-py3status"

Mon Oct 21 12:32:12 2019 rev:5 rq:741421 version:3.21

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-py3status/python-py3status.changes        
2019-09-11 10:39:35.827228562 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-py3status.new.2352/python-py3status.changes  
    2019-10-21 12:32:16.796224548 +0200
@@ -1,0 +2,9 @@
+Mon Oct 21 02:51:56 UTC 2019 - John Vandenberg <[email protected]>
+
+- Recommend i3status, with note that it is optional
+- Add configuration.rst to docs
+- Update to v3.21
+  * New module networkmanager
+  * many other fixes, see CHANGELOG
+
+-------------------------------------------------------------------

Old:
----
  py3status-3.20.tar.gz

New:
----
  py3status-3.21.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-py3status.spec ++++++
--- /var/tmp/diff_new_pack.cfPobE/_old  2019-10-21 12:32:17.524225373 +0200
+++ /var/tmp/diff_new_pack.cfPobE/_new  2019-10-21 12:32:17.528225378 +0200
@@ -18,9 +18,9 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-py3status
-Version:        3.20
+Version:        3.21
 Release:        0
-Summary:        Extensible i3status wrapper written in python
+Summary:        Python extensible i3status wrapper
 License:        BSD-3-Clause
 Group:          Development/Languages/Python
 URL:            https://github.com/ultrabug/py3status
@@ -32,6 +32,7 @@
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
 Requires:       python-setuptools
+Recommends:     i3status
 Recommends:     python-gevent >= 1.1
 Recommends:     python-pyudev >= 0.21.0
 BuildArch:      noarch
@@ -51,6 +52,9 @@
 - handling click events on your i3bar and play with them in no time
 - seeing your clock tick every second whatever your i3status interval
 
+py3status has a standalone mode allowing to bypass i3status when you need
+a py3status-modules-only i3bar.
+
 %prep
 %setup -q -n py3status-%{version}
 
@@ -77,7 +81,7 @@
 
 %files %{python_files}
 %license LICENSE
-%doc README.rst CHANGELOG
+%doc README.rst CHANGELOG doc/configuration.rst
 %python_alternative %{_bindir}/py3status
 %python_alternative %{_bindir}/py3-cmd
 %{python_sitelib}/*

++++++ py3status-3.20.tar.gz -> py3status-3.21.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/CHANGELOG new/py3status-3.21/CHANGELOG
--- old/py3status-3.20/CHANGELOG        2019-08-06 21:16:55.000000000 +0200
+++ new/py3status-3.21/CHANGELOG        2019-10-13 12:33:03.000000000 +0200
@@ -1,3 +1,23 @@
+version 3.21 (2019-10-13)
+* implement global request_retry_times and request_retry_wait options (#1847)
+* arch_updates module: checkupdates throws exit code on zero updates (#1848), 
by Daniel Jenssen
+* bitcoin_price module: change api request to http (#1836), by dosera
+* coin_market module: skip empty datas (#1849), by lasers
+* fix `long_description_content_type` missing
+* fix entry_point typo in docstring (#1830), by Oliver Bestwalter
+* fix project's long_description has invalid markup which will not be rendered 
on PyPI
+* i3status: support memory module, remove valid_config_param (#1833), by lasers
+* new module networkmanager: display network status (#1766), by Kevin Pulo
+* module testing: fix testmode fails because it uses is_gevent property. 
(#1832), by Valdur Kana
+* mpris module: fix KeyError exception closes #1827 (#1831), by lasers
+* nvidia_temp module: add safeformat for separator, rename separator (#1846), 
by lasers
+* spotify module: add playback placeholder (#1829), by Bazyli Cyran
+* sysdata module: prevent a divide by zero on empty swap (#1838), by Pierre 
GINDRAUD
+* weather_owm module: add safeformat for separator, rename separator (#1845), 
by lasers
+* weather_own module: add thresholds for humidity (#1844), by lasers
+* wifi module: fix bug introduced in PR #1834 (#1835), by ownaginatious
+* wifi module: specify device by name or MAC address (#1834), by ownaginatious
+
 version 3.20 (2019-08-06)
 * IMPORTANT: py3status now supports importing modules from pypi packages, see 
'writing modules' section on docs!
 * introduce entry point based discovery of packaged custom modules (#1823), by 
Oliver Bestwalter
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/PKG-INFO new/py3status-3.21/PKG-INFO
--- old/py3status-3.20/PKG-INFO 2019-08-06 21:24:51.000000000 +0200
+++ new/py3status-3.21/PKG-INFO 2019-10-13 12:40:27.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: py3status
-Version: 3.20
+Version: 3.21
 Summary: py3status: an extensible i3status wrapper written in python
 Home-page: https://github.com/ultrabug/py3status
 Author: Ultrabug
@@ -150,6 +150,6 @@
 Classifier: Programming Language :: Python :: 3.7
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
 Description-Content-Type: text/x-rst
-Provides-Extra: all
-Provides-Extra: gevent
 Provides-Extra: udev
+Provides-Extra: gevent
+Provides-Extra: all
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/doc/configuration.rst 
new/py3status-3.21/doc/configuration.rst
--- old/py3status-3.20/doc/configuration.rst    2019-06-27 15:59:41.000000000 
+0200
+++ new/py3status-3.21/doc/configuration.rst    2019-10-13 12:31:22.000000000 
+0200
@@ -937,9 +937,14 @@
     by all package managers.
 
 
-Request Timeout
+Request Settings
 --------------------------------------------------------------
 
+Handling timeouts
+^^^^^^^^^^^^^^^^^
+
+Timeouts are handled thanks to the global ``request_timeout`` setting.
+
 .. note::
     New in version 3.16
 
@@ -954,3 +959,34 @@
     exchange_rate {
         request_timeout = 10
     }
+
+
+Handling retries
+^^^^^^^^^^^^^^^^
+
+Retries are handled thanks to the global ``request_retry_times`` and
+``request_retry_wait`` settings.
+
+.. note::
+    New in version 3.21
+
+Requests failing due to network unavailability or remote server timeouts are
+retried automatically ``request_retry_times`` times (default ``3``) at a
+``request_retry_wait`` (default ``2``) seconds interval.
+
+This allows to be more graceful to i3 startup when network is not up yet or to
+short network disruptions and not display an error on the bar in that case.
+
+To find out if your module supports that, look for ``self.py3.request`` in the
+code.
+
+.. code-block:: py3status
+    :caption: Example
+
+    # try to contact the OWM API 10 times every 5 seconds before displaying
+    # an error on the bar for the module
+    # that is equivalent to 50 seconds of retrying before an error occurs
+    weather_owm {
+        request_retry_times = 10
+        request_retry_wait = 5
+    }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/py3status/constants.py 
new/py3status-3.21/py3status/constants.py
--- old/py3status-3.20/py3status/constants.py   2019-06-27 15:59:41.000000000 
+0200
+++ new/py3status-3.21/py3status/constants.py   2019-10-02 21:52:30.000000000 
+0200
@@ -23,6 +23,7 @@
     "cpu_temperature",
     "disk",
     "ethernet",
+    "memory",
     "path_exists",
     "run_watch",
     "tztime",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/py3status/core.py 
new/py3status-3.21/py3status/core.py
--- old/py3status-3.20/py3status/core.py        2019-08-06 21:10:22.000000000 
+0200
+++ new/py3status-3.21/py3status/core.py        2019-10-02 21:52:30.000000000 
+0200
@@ -503,7 +503,7 @@
         modules_list: ['weather_yahoo paris', 'pewpew', 'net_rate']
         user_modules: {
             'weather_yahoo': ('/etc/py3status.d/', 'weather_yahoo.py'),
-            'pewpew': (entry_point', <Py3Status class>),
+            'pewpew': ('entry_point', <Py3Status class>),
         }
         """
         for module in modules_list:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/py3status/i3status.py 
new/py3status-3.21/py3status/i3status.py
--- old/py3status-3.20/py3status/i3status.py    2019-04-20 18:39:38.000000000 
+0200
+++ new/py3status-3.21/py3status/i3status.py    2019-10-02 21:52:30.000000000 
+0200
@@ -255,22 +255,6 @@
         Thread.__init__(self)
         self.error = None
         self.i3modules = {}
-        self.i3status_module_names = [
-            "battery",
-            "cpu_temperature",
-            "cpu_usage",
-            "ddate",
-            "disk",
-            "ethernet",
-            "ipv6",
-            "load",
-            "path_exists",
-            "run_watch",
-            "time",
-            "tztime",
-            "volume",
-            "wireless",
-        ]
         self.i3status_pipe = None
         self.i3status_path = py3_wrapper.config["i3status_path"]
         self.json_list = None
@@ -304,20 +288,6 @@
             if module.is_time_module:
                 self.time_modules.append(module)
 
-    def valid_config_param(self, param_name, cleanup=False):
-        """
-        Check if a given section name is a valid parameter for i3status.
-        """
-        if cleanup:
-            valid_config_params = [
-                _
-                for _ in self.i3status_module_names
-                if _ not in ["cpu_usage", "ddate", "ipv6", "load", "time"]
-            ]
-        else:
-            valid_config_params = self.i3status_module_names + ["general", 
"order"]
-        return param_name.split(" ")[0] in valid_config_params
-
     def set_responses(self, json_list):
         """
         Set the given i3status responses on their respective configuration.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/py3status/module.py 
new/py3status-3.21/py3status/module.py
--- old/py3status-3.20/py3status/module.py      2019-08-06 21:10:22.000000000 
+0200
+++ new/py3status-3.21/py3status/module.py      2019-10-13 12:16:40.000000000 
+0200
@@ -60,6 +60,7 @@
         self.testing = self.config.get("testing")
         self.urgent = False
         self.i3bar_gaps_urgent_options = {}
+        self.hidden = False
 
         # create a nice name for the module that matches what the module is
         # called in the user config
@@ -300,11 +301,23 @@
             self.last_output = output
             self._py3_wrapper.notify_update(self.module_full_name, urgent)
 
+    def hide(self):
+        self.hidden = True
+        self.force_update()
+
+
+    def unhide(self):
+        self.hidden = Falses
+        self.wake()
+
     def get_latest(self):
         """
         return latest output.
         """
-        return self.last_output
+        if self.hidden:
+            return ""
+        else:
+            return self.last_output
 
     def set_module_options(self, module):
         """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/py3status/module_test.py 
new/py3status-3.21/py3status/module_test.py
--- old/py3status-3.20/py3status/module_test.py 2019-04-20 18:40:09.000000000 
+0200
+++ new/py3status-3.21/py3status/module_test.py 2019-10-02 21:52:30.000000000 
+0200
@@ -34,6 +34,7 @@
         self.lock = Event()
         self.output_modules = {}
         self.running = True
+        self.is_gevent = False
 
         self.lock.set()
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/py3status/modules/arch_updates.py 
new/py3status-3.21/py3status/modules/arch_updates.py
--- old/py3status-3.20/py3status/modules/arch_updates.py        2019-06-27 
15:59:41.000000000 +0200
+++ new/py3status-3.21/py3status/modules/arch_updates.py        2019-10-13 
12:16:47.000000000 +0200
@@ -78,8 +78,8 @@
         try:
             updates = self.py3.command_output(["checkupdates"])
             return len(updates.splitlines())
-        except self.py3.CommandError:
-            return None
+        except self.py3.CommandError as ce:
+            return None if ce.error else 0
 
     def _get_auracle_updates(self):
         try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/py3status/modules/bitcoin_price.py 
new/py3status-3.21/py3status/modules/bitcoin_price.py
--- old/py3status-3.20/py3status/modules/bitcoin_price.py       2019-04-20 
18:39:38.000000000 +0200
+++ new/py3status-3.21/py3status/modules/bitcoin_price.py       2019-10-02 
21:52:30.000000000 +0200
@@ -40,7 +40,6 @@
 """
 
 STRING_UNAVAILABLE = "N/A"
-STRING_ERROR = "bitcoin_price: site unreachable"
 
 
 class Py3status:
@@ -104,7 +103,7 @@
             "YEN": "¥",
         }
         self.last_price = 0
-        self.url = "https://api.bitcoincharts.com/v1/markets.json";
+        self.url = "http://api.bitcoincharts.com/v1/markets.json";
 
     def _get_price(self, data, market, field):
         """
@@ -116,15 +115,18 @@
                 return m[field]
 
     def bitcoin_price(self):
+        response = {
+            "full_text": "",
+            "cached_until": self.py3.time_in(self.cache_timeout),
+        }
+
         # get the data from bitcoincharts api
         try:
             data = self.py3.request(self.url).json()
-        except self.py3.RequestException:
-            return {
-                "cached_until": self.py3.time_in(self.cache_timeout),
-                "color": self.py3.COLOR_BAD,
-                "full_text": "" if self.hide_on_error else STRING_ERROR,
-            }
+        except self.py3.RequestException as err:
+            if self.hide_on_error:
+                return response
+            self.py3.error(str(err))
 
         # get the rate for each market given
         color_rate, rates, markets = None, [], self.markets.split(",")
@@ -151,8 +153,6 @@
                 )
             )
 
-        response = {"cached_until": self.py3.time_in(self.cache_timeout)}
-
         # colorize if an index is given or only one market is selected
         if len(rates) == 1 or self.color_index > -1:
             if self.last_price == 0:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/py3status/modules/coin_market.py 
new/py3status-3.21/py3status/modules/coin_market.py
--- old/py3status-3.20/py3status/modules/coin_market.py 2019-04-20 
18:40:09.000000000 +0200
+++ new/py3status-3.21/py3status/modules/coin_market.py 2019-10-13 
12:16:47.000000000 +0200
@@ -222,7 +222,7 @@
 
         # first_use bad? the user entered bad markets. stop here (error).
         # otherwise, make a limit for first time on 1000+ coins.
-        if data and self.first_use:
+        if self.first_use:
             self.first_use = False
             if not is_equal:
                 self.py3.error("bad markets")
@@ -271,7 +271,7 @@
     def coin_market(self):
         # first 1000+ coins (then %s coins)
         coin_data = self._get_coin_data()
-        if not self.limit:
+        if coin_data and not self.limit:
             # strip, compare, and maybe update again
             coin_data = self._organize_data(coin_data)
         data = self._manipulate_data(coin_data)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/py3status/modules/mpris.py 
new/py3status-3.21/py3status/modules/mpris.py
--- old/py3status-3.20/py3status/modules/mpris.py       2019-06-27 
15:59:41.000000000 +0200
+++ new/py3status-3.21/py3status/modules/mpris.py       2019-10-02 
21:52:30.000000000 +0200
@@ -394,7 +394,10 @@
         if not player_id.startswith(SERVICE_BUS):
             return False
 
-        player = self._dbus.get(player_id, SERVICE_BUS_URL)
+        try:
+            player = self._dbus.get(player_id, SERVICE_BUS_URL)
+        except KeyError:
+            return False
 
         if player.Identity not in self._mpris_names:
             self._mpris_names[player.Identity] = player_id.split(".")[-1]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/py3status/modules/networkmanager.py 
new/py3status-3.21/py3status/modules/networkmanager.py
--- old/py3status-3.20/py3status/modules/networkmanager.py      1970-01-01 
01:00:00.000000000 +0100
+++ new/py3status-3.21/py3status/modules/networkmanager.py      2019-10-02 
21:52:30.000000000 +0200
@@ -0,0 +1,184 @@
+# -*- coding: utf-8 -*-
+"""
+Display NetworkManager fields via nmcli, a command-line tool.
+
+Configuration parameters:
+    cache_timeout: refresh interval for this module (default 10)
+    devices: specify a list of devices to use (default ['[e|w]*'])
+    format: display format for this module (default '{format_device}')
+    format_device: format for devices
+        *(default "[\?if=general_connection {general_device}[\?soft  ]"
+        "[\?color=ap1_signal {ap1_ssid} {ap1_bars} {ap1_signal}%][\?soft  ]"
+        "[\?color=good {ip4_address1}]]")*
+    format_device_separator: show separator if more than one (default ' ')
+    thresholds: specify color thresholds to use
+        (default [(0, 'bad'), (30, 'degraded'), (65, 'good')])
+
+Format placeholders:
+    {format_device} format for devices
+
+Format_device placeholders:
+    {general_connection} eg Py3status, Wired Connection 1
+    {general_device}     eg wlp3s0b1, enp2s0
+    {general_type}       eg wifi, ethernet
+    {ap1_bars}           signal strength in bars, eg ▂▄▆_
+    {ap1_chan}           wifi channel, eg 6
+    {ap1_mode}           network mode, eg Adhoc or Infra
+    {ap1_rate}           bitrate, eg 54 Mbit/s
+    {ap1_security}       signal security, eg WPA2
+    {ap1_signal}         signal strength in percentage, eg 63
+    {ap1_ssid}           ssid name, eg Py3status
+    {ip4_address1}       eg 192.168.1.108
+    {ip6_address1}       eg 0000::0000:0000:0000:0000
+
+    Use `nmcli --terse --fields=general,ap,ip4,ip6 device show` for a full 
list of
+    supported NetworkManager fields to use. Not all of NetworkManager fields 
will
+    be usable. See `man nmcli` for more information.
+
+Color thresholds:
+    xxx: print a color based on the value of `xxx` placeholder
+
+Requires:
+    nmcli: cli configuration utility for NetworkManager
+
+Examples:
+```
+# specify devices to use
+networkmanager {
+    devices = ['e*']    # ethernet only
+    devices = ['w*']    # wireless only
+    devices = []        # ethernet, wireless, lo, etc
+}
+```
+
+@author Kevin Pulo <[email protected]>
+@license BSD
+
+SAMPLE OUTPUT
+[{'full_text': 'enp2s0 '}, {'color': '#00FF00', 'full_text': '192.168.1.108'}]
+
+wifi
+[
+    {'full_text': 'wlp3s0b1 '},
+    {'color': '#FFFF00', 'full_text': 'Py3net ▂▄__ 54% '},
+    {'color': '#00FF00', 'full_text': '192.168.1.106'},
+]
+"""
+
+from fnmatch import fnmatch
+
+STRING_NOT_INSTALLED = "not installed"
+
+
+class Py3status:
+    """
+    """
+
+    # available configuration parameters
+    cache_timeout = 10
+    devices = ["[e|w]*"]
+    format = "{format_device}"
+    format_device = (
+        "[\?if=general_connection {general_device}[\?soft  ]"
+        "[\?color=ap1_signal {ap1_ssid} {ap1_bars} {ap1_signal}%][\?soft  ]"
+        "[\?color=good {ip4_address1}]]"
+    )
+    format_device_separator = " "
+    thresholds = [(0, "bad"), (30, "degraded"), (65, "good")]
+
+    def post_config_hook(self):
+        command = "nmcli --terse --colors=no"
+        if not self.py3.check_commands(command.split()[0]):
+            raise Exception(STRING_NOT_INSTALLED)
+
+        self.first_run = True
+
+        addresses = [
+            x.split("_")[0]
+            for x in self.py3.get_placeholders_list(
+                self.format_device, "ip[46]_address[0123456789]"
+            )
+        ]
+
+        self.nmcli_command = "{} --fields={} device show".format(
+            command, ",".join(["general", "ap"] + addresses)
+        ).split()
+        self.caches = {"lines": {}, "devices": {}}
+        self.devices = {"list": [], "devices": self.devices}
+
+        self.thresholds_init = 
self.py3.get_color_names_list(self.format_device)
+
+    def _update_key(self, key):
+        for old, new in [("[", ""), ("]", ""), (".", "_"), ("-", "_")]:
+            key = key.replace(old, new)
+        return key.lower()
+
+    def networkmanager(self):
+        nm_data = self.py3.command_output(self.nmcli_command, localized=True)
+        new_device = []
+
+        for chunk in nm_data.split("\n\n"):
+            lines = chunk.splitlines()
+            key, value = lines[0].split(":", 1)
+            if self.first_run:
+                if self.devices["devices"]:
+                    for _filter in self.devices["devices"]:
+                        if fnmatch(value, _filter):
+                            self.devices["list"].append(value)
+            if value not in self.devices["list"]:
+                continue
+
+            try:
+                key = self.caches["devices"][key]
+            except KeyError:
+                new_key = self._update_key(key)
+
+                self.caches["devices"][key] = new_key
+                key = self.caches["devices"][key]
+
+            device = {key: value}
+
+            for line in lines[1:]:
+                try:
+                    key, value = self.caches["lines"][line]
+                except (KeyError, ValueError):
+                    key, value = line.split(":", 1)
+                    key = self._update_key(key)
+                    if "IP" in line and "ADDRESS" in line:
+                        value = value.split("/")[0]
+                    else:
+                        try:
+                            value = int(value)
+                        except ValueError:
+                            pass
+
+                    self.caches["lines"][line] = (key, value)
+
+                device[key] = value
+
+            for x in self.thresholds_init:
+                if x in device:
+                    self.py3.threshold_get_color(device[x], x)
+
+            new_device.append(self.py3.safe_format(self.format_device, device))
+
+        format_device_separator = 
self.py3.safe_format(self.format_device_separator)
+        format_device = self.py3.composite_join(format_device_separator, 
new_device)
+
+        self.first_run = False
+
+        return {
+            "cache_until": self.py3.time_in(self.cache_timeout),
+            "full_text": self.py3.safe_format(
+                self.format, {"format_device": format_device}
+            ),
+        }
+
+
+if __name__ == "__main__":
+    """
+    Run module in test mode.
+    """
+    from py3status.module_test import module_test
+
+    module_test(Py3status)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/py3status/modules/nvidia_temp.py 
new/py3status-3.21/py3status/modules/nvidia_temp.py
--- old/py3status-3.20/py3status/modules/nvidia_temp.py 2019-04-20 
18:40:09.000000000 +0200
+++ new/py3status-3.21/py3status/modules/nvidia_temp.py 2019-10-13 
12:16:47.000000000 +0200
@@ -6,7 +6,7 @@
     cache_timeout: refresh interval for this module (default 10)
     format: display format for this module (default 'GPU: {format_temp}')
     format_temp: display format for temperatures (default '{temp}°C')
-    temp_separator: temperature separator (if more than one) (default '|')
+    format_temp_separator: show separator if more than one (default ' ')
 
 Format placeholders:
     {format_temp} format for temperatures
@@ -43,7 +43,7 @@
     cache_timeout = 10
     format = "GPU: {format_temp}"
     format_temp = u"{temp}°C"
-    temp_separator = "|"
+    format_temp_separator = " "
 
     class Meta:
         def deprecate_function(config):
@@ -54,7 +54,16 @@
                 out["format"] = 
u"{}{{format_temp}}".format(config["format_prefix"])
             return out
 
-        deprecated = {"function": [{"function": deprecate_function}]}
+        deprecated = {
+            "function": [{"function": deprecate_function}],
+            "rename": [
+                {
+                    "param": "temp_separator",
+                    "new": "format_temp_separator",
+                    "msg": "obsolete parameter, use format_temp_separator",
+                }
+            ],
+        }
 
     def post_config_hook(self):
         if not self.py3.check_commands("nvidia-smi"):
@@ -72,8 +81,10 @@
         data = []
         for temp in temps:
             data.append(self.py3.safe_format(self.format_temp, {"temp": temp}))
-        data = self.py3.composite_join(self.temp_separator, data)
-        full_text = self.py3.safe_format(self.format, {"format_temp": data})
+
+        format_temp_separator = 
self.py3.safe_format(self.format_temp_separator)
+        format_temp = self.py3.composite_join(format_temp_separator, data)
+        full_text = self.py3.safe_format(self.format, {"format_temp": 
format_temp})
 
         return {
             "cached_until": self.py3.time_in(self.cache_timeout),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/py3status/modules/spotify.py 
new/py3status-3.21/py3status/modules/spotify.py
--- old/py3status-3.20/py3status/modules/spotify.py     2019-04-20 
18:40:09.000000000 +0200
+++ new/py3status-3.21/py3status/modules/spotify.py     2019-10-02 
21:52:30.000000000 +0200
@@ -21,6 +21,7 @@
 Format placeholders:
     {album} album name
     {artist} artiste name (first one)
+    {playback} state of the playback: Playing, Paused
     {time} time duration of the song
     {title} name of the song
 
@@ -55,12 +56,12 @@
 {'color': '#FF0000', 'full_text': 'Spotify stopped'}
 """
 
-import dbus
 import re
-
 from datetime import timedelta
 from time import sleep
 
+import dbus
+
 SPOTIFY_CMD = """dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify
                  /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.{cmd}"""
 
@@ -148,7 +149,7 @@
                 playback_status = self.player.Get(
                     "org.mpris.MediaPlayer2.Player", "PlaybackStatus"
                 )
-                if playback_status.strip() == "Playing":
+                if playback_status == "Playing":
                     color = self.py3.COLOR_PLAYING or self.py3.COLOR_GOOD
                 else:
                     color = self.py3.COLOR_PAUSED or self.py3.COLOR_DEGRADED
@@ -161,7 +162,13 @@
             return (
                 self.py3.safe_format(
                     self.format,
-                    dict(title=title, artist=artist, album=album, time=rtime),
+                    dict(
+                        title=title,
+                        artist=artist,
+                        album=album,
+                        time=rtime,
+                        playback=playback_status,
+                    ),
                 ),
                 color,
             )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/py3status/modules/sysdata.py 
new/py3status-3.21/py3status/modules/sysdata.py
--- old/py3status-3.20/py3status/modules/sysdata.py     2019-06-27 
15:59:41.000000000 +0200
+++ new/py3status-3.21/py3status/modules/sysdata.py     2019-10-02 
21:52:30.000000000 +0200
@@ -330,7 +330,10 @@
             total_mem_kib = meminfo["SwapTotal:"]
             used_mem_kib = total_mem_kib - meminfo["SwapFree:"]
 
-        used_percent = 100 * used_mem_kib / total_mem_kib
+        if total_mem_kib == 0:
+            used_percent = 0
+        else:
+            used_percent = 100 * used_mem_kib / total_mem_kib
 
         unit = "B" if unit == "dynamic" else unit
         (total, total_unit) = self.py3.format_units(total_mem_kib * 1024, unit)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/py3status/modules/weather_owm.py 
new/py3status-3.21/py3status/modules/weather_owm.py
--- old/py3status-3.20/py3status/modules/weather_owm.py 2019-07-04 
23:21:16.000000000 +0200
+++ new/py3status-3.21/py3status/modules/weather_owm.py 2019-10-13 
12:16:47.000000000 +0200
@@ -44,8 +44,6 @@
         (default 3)
     forecast_include_today: Include today in the forecast? (Boolean)
         (default False)
-    forecast_text_separator: Separator between entries in the forecast
-        (default ' ')
     format: How to display the weather
         This also dictates the type of forecast. The placeholders here refer to
         the format_[...] variables found below.
@@ -64,6 +62,8 @@
         for future weather. Notably, this does not include information about
         sunrise or sunset times.
         (default '{icon}')
+    format_forecast_separator: Separator between entries in the forecast
+        (default ' ')
     format_humidity: Formatting for humidity (percentage)
         Available placeholders:
             icon, humidity
@@ -317,10 +317,10 @@
     country = None
     forecast_days = 3
     forecast_include_today = False
-    forecast_text_separator = " "
     format = "{city} {icon} {temperature}[ {rain}], {description} {forecast}"
     format_clouds = "{icon} {coverage}%"
     format_forecast = "{icon}"
+    format_forecast_separator = " "
     format_humidity = "{icon} {humidity}%"
     format_pressure = "{icon} {pressure} hPa"
     format_rain = "[\?if=amount {icon} {amount:.0f} {unit}]"
@@ -352,7 +352,16 @@
     unit_wind = "mph"
 
     class Meta:
-        deprecated = {"remove": [{"param": "offset_gmt", "msg": "obsolete"}]}
+        deprecated = {
+            "remove": [{"param": "offset_gmt", "msg": "obsolete"}],
+            "rename": [
+                {
+                    "param": "forecast_text_separator",
+                    "new": "format_forecast_separator",
+                    "msg": "obsolete parameter, use format_forecast_separator",
+                }
+            ],
+        }
 
     def _get_icons(self):
         if self.icons is None:
@@ -425,6 +434,13 @@
                 if name not in self.thresholds:
                     self.thresholds[name] = self.thresholds[THRESHOLDS_ALL]
 
+        # Initialize per-format thresholds
+        self.thresholds_init = {}
+        for name in ("format_humidity",):
+            self.thresholds_init[name] = self.py3.get_color_names_list(
+                getattr(self, name)
+            )
+
     def _make_req(self, url, params=None):
         # Make a request expecting a JSON response
         req = self.py3.request(url, params=params)
@@ -618,11 +634,16 @@
 
     def _format_humidity(self, wthr):
         # Format the humidity (default zero humidity)
-        humidity = self._jpath(wthr, OWM_HUMIDITY, 0)
+        humidity_data = {
+            "icon": self.icon_humidity,
+            "humidity": self._jpath(wthr, OWM_HUMIDITY, 0),
+        }
 
-        return self.py3.safe_format(
-            self.format_humidity, {"icon": self.icon_humidity, "humidity": 
humidity}
-        )
+        for x in self.thresholds_init["format_humidity"]:
+            if x in humidity_data:
+                self.py3.threshold_get_color(humidity_data[x], x)
+
+        return self.py3.safe_format(self.format_humidity, humidity_data)
 
     def _format_pressure(self, wthr):
         # Get data and add the icon
@@ -725,8 +746,9 @@
             forecasts.append(self.py3.safe_format(self.format_forecast, 
future))
 
         # Give the final format
+        format_forecast_separator = 
self.py3.safe_format(self.format_forecast_separator)
         today["forecast"] = self.py3.composite_join(
-            self.forecast_text_separator, forecasts
+            format_forecast_separator, forecasts
         )
 
         return self.py3.safe_format(self.format, today)
@@ -806,6 +828,6 @@
             "format_forecast": ("{icon} " + all_string),
             # Miscellaneous
             "forecast_days": 1,
-            "forecast_text_separator": "//",
+            "format_forecast_separator": "//",
         },
     )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/py3status/modules/wifi.py 
new/py3status-3.21/py3status/modules/wifi.py
--- old/py3status-3.20/py3status/modules/wifi.py        2019-06-27 
15:59:41.000000000 +0200
+++ new/py3status-3.21/py3status/modules/wifi.py        2019-10-02 
21:52:30.000000000 +0200
@@ -8,7 +8,8 @@
     blocks: a string, where each character represents quality level
         (default "_▁▂▃▄▅▆▇█")
     cache_timeout: Update interval in seconds (default 10)
-    device: specify device name to use, otherwise auto (default None)
+    device: specify name or MAC address of device to use, otherwise auto
+        (default None)
     down_color: Output color when disconnected, possible values:
         "good", "degraded", "bad" (default "bad")
     format: Display format for this module
@@ -106,11 +107,16 @@
             data = self.py3.command_output([iw, "dev"])
         except self.py3.CommandError as ce:
             raise Exception(ce.error.strip())
+        last_device = None
         for line in data.splitlines()[1:]:
-            if "Interface" in line:
-                device = line.split()[-1]
-                if not self.device or device == self.device:
-                    self.device = device
+            if not line.startswith("\t\t"):
+                last_device = None
+            if "Interface" in line or ("addr" in line and last_device is not 
None):
+                intf_or_addr = line.split()[-1]
+                if "Interface" in line:
+                    last_device = intf_or_addr
+                if not self.device or intf_or_addr.lower() == 
self.device.lower():
+                    self.device = last_device
                     break
         else:
             device = " `{}`".format(self.device) if self.device else ""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/py3status/py3.py 
new/py3status-3.21/py3status/py3.py
--- old/py3status-3.20/py3status/py3.py 2019-07-04 10:58:01.000000000 +0200
+++ new/py3status-3.21/py3status/py3.py 2019-10-13 12:31:22.000000000 +0200
@@ -1254,6 +1254,8 @@
         timeout=None,
         auth=None,
         cookiejar=None,
+        retry_times=None,
+        retry_wait=None,
     ):
         """
         Make a request to a url and retrieve the results.
@@ -1270,6 +1272,8 @@
         :param timeout: timeout for the request in seconds
         :param auth: authentication info as tuple `(username, password)`
         :param cookiejar: an object of a CookieJar subclass
+        :param retry_times: how many times to retry the request
+        :param retry_wait: how long to wait between retries in seconds
 
         :returns: HttpResponse
         """
@@ -1289,15 +1293,36 @@
         if timeout is None:
             timeout = getattr(self._py3status_module, "request_timeout", 10)
 
+        if retry_times is None:
+            retry_times = getattr(self._py3status_module, 
"request_retry_times", 3)
+
+        if retry_wait is None:
+            retry_wait = getattr(self._py3status_module, "request_retry_wait", 
2)
+
         if "User-Agent" not in headers:
             headers["User-Agent"] = "py3status/{} {}".format(version, 
self._uid)
 
-        return HttpResponse(
-            url,
-            params=params,
-            data=data,
-            headers=headers,
-            timeout=timeout,
-            auth=auth,
-            cookiejar=cookiejar,
-        )
+        def get_http_response():
+            return HttpResponse(
+                url,
+                params=params,
+                data=data,
+                headers=headers,
+                timeout=timeout,
+                auth=auth,
+                cookiejar=cookiejar,
+            )
+
+        for n in range(1, retry_times):
+            try:
+                return get_http_response()
+            except (self.RequestTimeout, self.RequestURLError):
+                if self.is_gevent():
+                    from gevent import sleep
+                else:
+                    from time import sleep
+                self.log("HTTP request retry {}/{}".format(n, retry_times))
+                sleep(retry_wait)
+        self.log("HTTP request retry {}/{}".format(retry_times, retry_times))
+        sleep(retry_wait)
+        return get_http_response()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/py3status/tester.py 
new/py3status-3.21/py3status/tester.py
--- old/py3status-3.20/py3status/tester.py      1970-01-01 01:00:00.000000000 
+0100
+++ new/py3status-3.21/py3status/tester.py      2019-10-12 18:01:48.000000000 
+0200
@@ -0,0 +1,30 @@
+import json
+from time import sleep
+import sys
+from syslog import syslog
+
+o = sys.__stdout__
+
+def out(msg):
+    o.write(msg + "\n")
+    o.flush()
+
+out('{"version":1}')
+out('[')
+
+j = {
+    "name": "test",
+    "instance": "",
+    "full_text": "M",
+    "short_text": ".",
+}
+
+N = 1
+
+out("[" + json.dumps(j) + "]")
+while True:
+    if len(j["full_text"]) < 137:
+        j["full_text"] += "M"
+#    syslog("{}".format(len(j["full_text"])))
+    out(",[" + json.dumps(j) + "]")
+    sleep(0.005)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/py3status/version.py 
new/py3status-3.21/py3status/version.py
--- old/py3status-3.20/py3status/version.py     2019-08-06 21:16:20.000000000 
+0200
+++ new/py3status-3.21/py3status/version.py     2019-10-13 12:33:15.000000000 
+0200
@@ -1 +1 @@
-version = "3.20"
+version = "3.21"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/py3status.egg-info/PKG-INFO 
new/py3status-3.21/py3status.egg-info/PKG-INFO
--- old/py3status-3.20/py3status.egg-info/PKG-INFO      2019-08-06 
21:24:51.000000000 +0200
+++ new/py3status-3.21/py3status.egg-info/PKG-INFO      2019-10-13 
12:40:26.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: py3status
-Version: 3.20
+Version: 3.21
 Summary: py3status: an extensible i3status wrapper written in python
 Home-page: https://github.com/ultrabug/py3status
 Author: Ultrabug
@@ -150,6 +150,6 @@
 Classifier: Programming Language :: Python :: 3.7
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
 Description-Content-Type: text/x-rst
-Provides-Extra: all
-Provides-Extra: gevent
 Provides-Extra: udev
+Provides-Extra: gevent
+Provides-Extra: all
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/py3status-3.20/py3status.egg-info/SOURCES.txt 
new/py3status-3.21/py3status.egg-info/SOURCES.txt
--- old/py3status-3.20/py3status.egg-info/SOURCES.txt   2019-08-06 
21:24:51.000000000 +0200
+++ new/py3status-3.21/py3status.egg-info/SOURCES.txt   2019-10-13 
12:40:26.000000000 +0200
@@ -55,6 +55,7 @@
 py3status/request.py
 py3status/screenshots.py
 py3status/storage.py
+py3status/tester.py
 py3status/udev_monitor.py
 py3status/util.py
 py3status/version.py
@@ -123,6 +124,7 @@
 py3status/modules/net_iplist.py
 py3status/modules/net_rate.py
 py3status/modules/netdata.py
+py3status/modules/networkmanager.py
 py3status/modules/ns_checker.py
 py3status/modules/nvidia_smi.py
 py3status/modules/nvidia_temp.py


Reply via email to