Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-py3status for
openSUSE:Factory checked in at 2023-03-08 14:52:46
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-py3status (Old)
and /work/SRC/openSUSE:Factory/.python-py3status.new.31432 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-py3status"
Wed Mar 8 14:52:46 2023 rev:10 rq:1069990 version:3.49
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-py3status/python-py3status.changes
2022-10-03 20:08:11.061382268 +0200
+++
/work/SRC/openSUSE:Factory/.python-py3status.new.31432/python-py3status.changes
2023-03-08 14:52:50.250762600 +0100
@@ -1,0 +2,28 @@
+Tue Feb 28 10:14:23 UTC 2023 - Dawid Adam <[email protected]>
+
+- Update to 3.49:
+ * do_not_disturb module: use 'makoctl mode' to check current mode. (#2172),
by Valdur Kana
+ * google_calendar module: add support to configure which google calendar
will be used (#2174), by Alex Thomae
+
+-------------------------------------------------------------------
+Tue Feb 28 10:14:23 UTC 2023 - Dawid Adam <[email protected]>
+
+- Update to 3.48:
+ * IMPORTANT: bluetooth module has been replaced by the bluetooth2 code,
please migrate
+ * python: drop py 3.6 from CI and bump 3.11 (#2166)
+ * battery_level module: allow icon to not use charging_character (#2158), by
Kevin Pulo
+ * bluetooth module: replaced by bluetooth2 as announced on 2022-10
+ * check_tcp module: add IPv6 support (#2167), by Björn Busse
+ * clock module: migrate to standard zoneinfo with 3.7, 3.8 support. (#2155),
by Valdur Kana
+ * events: change the reading timeout to infinity (#2153), by Austin Lund
+ * kdeconnector module: Active notifications were always 1. (#2170), by
Valdur Kana
+ * kdeconnector module: refactor to use dbus signals to update module
(#2168), by Valdur Kana
+ * kdeconnector module: show cell network type and strength. (#2162) (#2163),
by Valdur Kana
+ * mpris module: fix error self.parent on Py3status module not found.
(#2169), by Valdur Kana
+ * timewarrior module: remove dependency on dateutil (#2161), by Rasmus Rendal
+ * volume_status module: amixer scontrols uses device and card parameter.
(#2152), by Valdur Kana
+ * volume_status module: deprecate start_delay parameter
+ * volume_status module: smarter initialization logic with retry, remove
start_delay setting (#2165), by Joan Bruguera
+ * window module: window without title will not produce error on i3msg mode,
by Valdur Kana* core: add inhibition timer on misbehaving signals
+
+-------------------------------------------------------------------
Old:
----
py3status-3.47.tar.gz
New:
----
py3status-3.49.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-py3status.spec ++++++
--- /var/tmp/diff_new_pack.gbZQr1/_old 2023-03-08 14:52:50.738765258 +0100
+++ /var/tmp/diff_new_pack.gbZQr1/_new 2023-03-08 14:52:50.742765279 +0100
@@ -1,7 +1,7 @@
#
# spec file for package python-py3status
#
-# Copyright (c) 2022 SUSE LLC
+# Copyright (c) 2023 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -19,7 +19,7 @@
%define skip_python2 1
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-py3status
-Version: 3.47
+Version: 3.49
Release: 0
Summary: Python extensible i3status wrapper
License: BSD-3-Clause
@@ -32,6 +32,8 @@
BuildRequires: fdupes
BuildRequires: python-rpm-macros
Requires: python-setuptools
+Requires(post): update-alternatives
+Requires(postun):update-alternatives
Recommends: i3status
Recommends: python-gevent >= 1.1
Recommends: python-pyudev >= 0.21.0
@@ -73,7 +75,7 @@
%python_install_alternative py3status
%python_install_alternative py3-cmd
-%preun
+%postun
%python_uninstall_alternative py3status
%python_uninstall_alternative py3-cmd
@@ -82,6 +84,6 @@
%doc CHANGELOG README.md
%python_alternative %{_bindir}/py3status
%python_alternative %{_bindir}/py3-cmd
-%{python_sitelib}/*
+%{python_sitelib}/py3status*
%changelog
++++++ py3status-3.47.tar.gz -> py3status-3.49.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/.github/workflows/ci.yml
new/py3status-3.49/.github/workflows/ci.yml
--- old/py3status-3.47/.github/workflows/ci.yml 2022-03-14 10:30:28.000000000
+0100
+++ new/py3status-3.49/.github/workflows/ci.yml 2022-12-12 08:07:52.000000000
+0100
@@ -8,7 +8,7 @@
strategy:
max-parallel: 5
matrix:
- python-version: [3.6, 3.7, 3.8, 3.9, "3.10"]
+ python-version: [3.7, 3.8, 3.9, "3.10", "3.11"]
steps:
- uses: actions/checkout@v1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/CHANGELOG new/py3status-3.49/CHANGELOG
--- old/py3status-3.47/CHANGELOG 2022-10-02 17:52:20.000000000 +0200
+++ new/py3status-3.49/CHANGELOG 2023-02-17 13:40:27.000000000 +0100
@@ -1,3 +1,25 @@
+version 3.49 (2023-02-17)
+* do_not_disturb module: use 'makoctl mode' to check current mode. (#2172), by
Valdur Kana
+* google_calendar module: add support to configure which google calendar will
be used (#2174), by Alex Thomae
+
+version 3.48 (2023-01-14)
+* IMPORTANT: bluetooth module has been replaced by the bluetooth2 code, please
migrate
+* python: drop py 3.6 from CI and bump 3.11 (#2166)
+* battery_level module: allow icon to not use charging_character (#2158), by
Kevin Pulo
+* bluetooth module: replaced by bluetooth2 as announced on 2022-10
+* check_tcp module: add IPv6 support (#2167), by Björn Busse
+* clock module: migrate to standard zoneinfo with 3.7, 3.8 support. (#2155),
by Valdur Kana
+* events: change the reading timeout to infinity (#2153), by Austin Lund
+* kdeconnector module: Active notifications were always 1. (#2170), by Valdur
Kana
+* kdeconnector module: refactor to use dbus signals to update module (#2168),
by Valdur Kana
+* kdeconnector module: show cell network type and strength. (#2162) (#2163),
by Valdur Kana
+* mpris module: fix error self.parent on Py3status module not found. (#2169),
by Valdur Kana
+* timewarrior module: remove dependency on dateutil (#2161), by Rasmus Rendal
+* volume_status module: amixer scontrols uses device and card parameter.
(#2152), by Valdur Kana
+* volume_status module: deprecate start_delay parameter
+* volume_status module: smarter initialization logic with retry, remove
start_delay setting (#2165), by Joan Bruguera
+* window module: window without title will not produce error on i3msg mode, by
Valdur Kana* core: add inhibition timer on misbehaving signals
+
version 3.47 (2022-10-02)
* INFORMATION: the upcoming bluetooth module has been merged as bluetooth2,
users are encouraged to switch
* core: simpler logic to inhibit out of order signaling (#2147)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/PKG-INFO new/py3status-3.49/PKG-INFO
--- old/py3status-3.47/PKG-INFO 2022-10-02 17:54:02.083479200 +0200
+++ new/py3status-3.49/PKG-INFO 2023-02-17 13:41:23.554134000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: py3status
-Version: 3.47
+Version: 3.49
Summary: py3status: an extensible i3status wrapper written in python
Home-page: https://github.com/ultrabug/py3status
Author: Ultrabug
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/py3status/core.py
new/py3status-3.49/py3status/core.py
--- old/py3status-3.47/py3status/core.py 2022-10-02 17:50:25.000000000
+0200
+++ new/py3status-3.49/py3status/core.py 2022-10-27 12:10:18.000000000
+0200
@@ -251,6 +251,7 @@
"""
self.config = vars(options)
self.i3bar_running = True
+ self.inhibit_signal_ts = time.monotonic()
self.last_refresh_ts = time.monotonic()
self.lock = Event()
self.modules = {}
@@ -1018,7 +1019,10 @@
return ",".join(dumps(x) for x in outputs)
def i3bar_stop(self, signum, frame):
- if self.next_allowed_signal == signum:
+ if (
+ self.next_allowed_signal == signum
+ and time.monotonic() > self.inhibit_signal_ts
+ ):
self.log(f"received stop_signal {Signals(signum).name}")
self.i3bar_running = False
# i3status should be stopped
@@ -1027,15 +1031,20 @@
self.next_allowed_signal = SIGCONT
else:
self.log(f"inhibited stop_signal {Signals(signum).name}",
level="warning")
+ self.inhibit_signal_ts = time.monotonic() + 0.1
def i3bar_start(self, signum, frame):
- if self.next_allowed_signal == signum:
+ if (
+ self.next_allowed_signal == signum
+ and time.monotonic() > self.inhibit_signal_ts
+ ):
self.log(f"received resume signal {Signals(signum).name}")
self.i3bar_running = True
self.wake_modules()
self.next_allowed_signal = self.stop_signal
else:
self.log(f"inhibited start_signal {Signals(signum).name}",
level="warning")
+ self.inhibit_signal_ts = time.monotonic() + 0.1
def sleep_modules(self):
# Put all py3modules to sleep so they stop updating
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/py3status/events.py
new/py3status-3.49/py3status/events.py
--- old/py3status-3.47/py3status/events.py 2022-02-17 12:08:39.000000000
+0100
+++ new/py3status-3.49/py3status/events.py 2022-10-17 13:35:26.000000000
+0200
@@ -272,7 +272,7 @@
"""
try:
while self.py3_wrapper.running:
- event_str = self.poller_inp.readline()
+ event_str = self.poller_inp.readline(timeout=None)
if not event_str:
continue
try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/py3status/module.py
new/py3status-3.49/py3status/module.py
--- old/py3status-3.47/py3status/module.py 2022-10-02 17:37:33.000000000
+0200
+++ new/py3status-3.49/py3status/module.py 2023-01-09 18:39:16.000000000
+0100
@@ -5,6 +5,7 @@
from importlib.machinery import SourceFileLoader
from pathlib import Path
from random import randint
+from types import FunctionType
from py3status.composite import Composite
from py3status.constants import MARKUP_LANGUAGES, ON_ERROR_VALUES, POSITIONS
@@ -845,8 +846,8 @@
if method.startswith("_"):
continue
else:
- m_type = type(getattr(class_inst, method))
- if "method" in str(m_type):
+ m_attr = inspect.getattr_static(class_inst, method)
+ if isinstance(m_attr, FunctionType):
params_type = self._params_type(method, class_inst)
if method == "on_click":
self.click_events = params_type
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/py3status/modules/battery_level.py
new/py3status-3.49/py3status/modules/battery_level.py
--- old/py3status-3.47/py3status/modules/battery_level.py 2022-10-02
16:25:48.000000000 +0200
+++ new/py3status-3.49/py3status/modules/battery_level.py 2023-01-09
18:41:34.000000000 +0100
@@ -12,6 +12,7 @@
(default 60)
charging_character: a character to represent charging battery
especially useful when using icon fonts (e.g. FontAwesome)
+ set to 'None' if you want to hide the charging state of your battery
(default "â¡")
format: string that formats the output. See placeholders below.
(default "{icon}")
@@ -477,7 +478,7 @@
self.status = self.format_status_discharging
def _update_icon(self):
- if self.charging:
+ if self.charging and self.charging_character is not None:
self.icon = self.charging_character
else:
self.icon = self.blocks[
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/py3status/modules/bluetooth.py
new/py3status-3.49/py3status/modules/bluetooth.py
--- old/py3status-3.47/py3status/modules/bluetooth.py 2022-10-02
16:25:48.000000000 +0200
+++ new/py3status-3.49/py3status/modules/bluetooth.py 2023-01-10
13:36:52.000000000 +0100
@@ -3,54 +3,92 @@
Configuration parameters:
cache_timeout: refresh interval for this module (default 10)
- format: display format for this module (default 'BT[: {format_device}]')
- format_device: display format for bluetooth devices (default '{name}')
- format_separator: show separator if more than one (default '\|')
+ format: display format for this module (default "{format_adapter}")
+ format_adapter: display format for adapters (default "{format_device}")
+ format_adapter_separator: show separator if more than one (default " ")
+ format_device: display format for devices
+ (default "\?if=connected&color=connected {alias}")
+ format_device_separator: show separator if more than one (default " ")
+ thresholds: specify color thresholds to use
+ (default [(False, "bad"), (True, "good")])
Format placeholders:
- {format_device} format for bluetooth devices
+ {format_adapter} format for adapters
+ {adapter} number of adapters, eg 1
+
+format_adapter placeholders:
+ {format_device} format for devices
+ {device} number of devices, eg 5
+ {address} eg, 00:00:00:00:00:00
+ {addresstype} eg, public
+ {alias} eg, thinkpad
+ {class} eg, 123456
+ {discoverable} eg, False
+ {discoverabletimeout} eg, 0
+ {discovering} eg, False
+ {modalias} eg, usb:v1D68234ABCDEF5
+ {name} eg, z420
+ {pairable} eg, True
+ {pairabletimeout} eg, 0
+ {path} eg, /org/bluez/hci0
+ {powered} eg, True
+ {uuids} eg, []
format_device placeholders:
- {mac} bluetooth device address
- {name} bluetooth device name
+ {adapter} eg, /org/bluez/hci0
+ {address} eg, 00:00:00:00:00:00
+ {addresstype} eg, public
+ {alias} eg, MSFT Mouse
+ {class} eg, 1234
+ {connected} eg, False
+ {icon} eg, input-mouse
+ {legacypairing} eg, False
+ {modalias} eg, usb:v1D68234ABCDEF5
+ {name} eg, Microsoft Bluetooth Notebook Mouse 5000
+ {paired} eg, True
+ {servicesresolved} eg, False
+ {trusted} eg, True
+ {uuids} eg, []
-Color options:
- color_bad: No connection
- color_good: Active connection
+Color thresholds:
+ xxx: print a color based on the value of `xxx` placeholder
Requires:
- pydbus: pythonic dbus library
pygobject: Python bindings for GObject Introspection
-@author jmdana <https://github.com/jmdana>
-@license GPLv3 <https://www.gnu.org/licenses/gpl-3.0.txt>
+Examples:
+```
+# always display devices
+bluetooth {
+ format_device = "\?color=connected {alias}"
+}
+
+# set an alias via blueman-manager or bluetoothctl
+# $ bluetoothctl
+# [bluetooth] # devices
+# [bluetooth] # connect 00:00:00:00:00:00
+# [bluetooth] # set-alias "MSFT Mouse"
+
+# display missing adapter (feat. request)
+bluetooth {
+ format = "\?if=adapter {format_adapter}|\?color=darkgray No Adapter"
+}
+
+# legacy default
+bluetooth {
+ format = "\?color=good BT: {format_adapter}|\?color=bad BT"
+ format_device_separator = "\|"
+}
+```
-SAMPLE OUTPUT
-{'color': '#00FF00', 'full_text': u'BT: Microsoft Bluetooth Notebook Mouse
5000'}
+@author jmdana, lasers
+@license BSD
-off
-{'color': '#FF0000', 'full_text': u'BT'}
+SAMPLE OUTPUT
+{'color': '#00FF00', 'full_text': u'Microsoft Bluetooth Notebook Mouse 5000'}
"""
-from pydbus import SystemBus
-
-DEFAULT_FORMAT = "BT[: {format_device}]"
-
-
-def get_connected_devices():
- bus = SystemBus()
- manager = bus.get("org.bluez", "/")["org.freedesktop.DBus.ObjectManager"]
- objects = manager.GetManagedObjects()
- devices = []
-
- for dev_path, interfaces in objects.items():
- if "org.bluez.Device1" in interfaces:
- properties = objects[dev_path]["org.bluez.Device1"]
-
- if properties["Connected"] == 1:
- devices.append((properties["Address"], properties["Name"]))
-
- return devices
+from gi.repository import Gio
class Py3status:
@@ -58,87 +96,93 @@
# available configuration parameters
cache_timeout = 10
- format = DEFAULT_FORMAT
- format_device = "{name}"
- format_separator = r"\|"
-
- class Meta:
- def deprecate_function(config):
- if not config.get("format_separator") and
config.get("device_separator"):
- sep = config.get("device_separator")
- sep = sep.replace("\\", "\\\\")
- sep = sep.replace("[", r"\[")
- sep = sep.replace("]", r"\]")
- sep = sep.replace("|", r"\|")
-
- return {"format_separator": sep}
- else:
- return {}
-
- deprecated = {
- "function": [{"function": deprecate_function}],
- "remove": [
- {
- "param": "device_separator",
- "msg": "obsolete set using `format_separator`",
- }
- ],
- }
+ format = "{format_adapter}"
+ format_adapter = "{format_device}"
+ format_adapter_separator = " "
+ format_device = "\?if=connected&color=connected {alias}"
+ format_device_separator = " "
+ thresholds = [(False, "bad"), (True, "good")]
def post_config_hook(self):
- # DEPRECATION WARNING. SPECIAL CASE. DO NOT USE THIS AS EXAMPLE.
- format_prefix = getattr(self, "format_prefix", None)
- format_no_conn = getattr(self, "format_no_conn", None)
- format_no_conn_prefix = getattr(self, "format_no_conn_prefix", None)
-
- placeholders = set(self.py3.get_placeholders_list(self.format))
- if {"name", "mac"} & placeholders:
- # this is an old format so should be format_device
- self.format_device = self.format
- self.format = DEFAULT_FORMAT
- msg = "DEPRECATION WARNING: your format is using invalid "
- msg += "placeholders you should update your configuration."
- self.py3.log(msg)
-
- if self.format != DEFAULT_FORMAT:
- # The user has set a format using the new style format so we are
- # done here.
- return
-
- if format_prefix or format_no_conn_prefix or format_no_conn:
- # create a format that will give the expected output
- self.format = r"[\?if=format_device
{}{{format_device}}|{}{}]".format(
- format_prefix or "BT: ",
- format_no_conn_prefix or "BT: ",
- format_no_conn or "OFF",
+ bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None)
+ iface = "org.freedesktop.DBus.ObjectManager"
+ self.bluez_manager = Gio.DBusProxy.new_sync(
+ bus, Gio.DBusProxyFlags.NONE, None, "org.bluez", "/", iface, None
+ )
+
+ self.names_and_matches = [
+ ("adapters", "org.bluez.Adapter1"),
+ ("devices", "org.bluez.Device1"),
+ ]
+
+ self.thresholds_init = {}
+ for name in ["format", "format_adapter", "format_device"]:
+ self.thresholds_init[name] = self.py3.get_color_names_list(
+ getattr(self, name)
)
- msg = "DEPRECATION WARNING: you are using old style configuration "
- msg += "parameters you should update to use the new format."
- self.py3.log(msg)
+
+ def _get_bluez_data(self):
+ objects = self.bluez_manager.GetManagedObjects()
+ temporary = {}
+
+ for path, interfaces in sorted(objects.items()):
+ interface_keys = interfaces.keys()
+ for name, match in self.names_and_matches:
+ if match in interface_keys:
+ interface = {k.lower(): v for k, v in
interfaces[match].items()}
+ interface.update({"path": path, "uuids": []})
+ temporary.setdefault(name, []).append(interface)
+ break
+
+ for device in temporary.pop("devices", []):
+ for index, adapter in enumerate(temporary["adapters"]):
+ if device["adapter"] == adapter["path"]:
+ temporary["adapters"][index].setdefault("devices",
[]).append(
+ device
+ )
+ break
+
+ return temporary
def bluetooth(self):
- devices = get_connected_devices()
+ bluez_data = self._get_bluez_data()
+ adapters = bluez_data.pop("adapters", [])
+ new_adapter = []
+
+ for adapter in adapters:
+ devices = adapter.pop("devices", [])
+ new_device = []
+
+ for device in devices:
+ for x in self.thresholds_init["format_device"]:
+ 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)
+
+ adapter.update({"format_device": format_device, "device":
len(devices)})
+
+ for x in self.thresholds_init["format_adapter"]:
+ if x in adapter:
+ self.py3.threshold_get_color(adapter[x], x)
+
+ new_adapter.append(self.py3.safe_format(self.format_adapter,
adapter))
+
+ format_adapter_separator =
self.py3.safe_format(self.format_adapter_separator)
+ format_adapter = self.py3.composite_join(format_adapter_separator,
new_adapter)
+
+ bluetooth_data = {"format_adapter": format_adapter, "adapter":
len(adapters)}
- if devices:
- data = []
- for mac, name in devices:
- data.append(
- self.py3.safe_format(self.format_device, {"name": name,
"mac": mac})
- )
-
- format_separator = self.py3.safe_format(self.format_separator)
- format_device = self.py3.composite_join(format_separator, data)
- color = self.py3.COLOR_GOOD
- else:
- format_device = None
- color = self.py3.COLOR_BAD
+ for x in self.thresholds_init["format"]:
+ if x in bluetooth_data:
+ self.py3.threshold_get_color(bluetooth_data[x], x)
return {
"cached_until": self.py3.time_in(self.cache_timeout),
- "full_text": self.py3.safe_format(
- self.format, {"format_device": format_device}
- ),
- "color": color,
+ "full_text": self.py3.safe_format(self.format, bluetooth_data),
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/py3status/modules/bluetooth2.py
new/py3status-3.49/py3status/modules/bluetooth2.py
--- old/py3status-3.47/py3status/modules/bluetooth2.py 2022-10-02
15:59:23.000000000 +0200
+++ new/py3status-3.49/py3status/modules/bluetooth2.py 1970-01-01
01:00:00.000000000 +0100
@@ -1,195 +0,0 @@
-r"""
-Display bluetooth status.
-
-Configuration parameters:
- cache_timeout: refresh interval for this module (default 10)
- format: display format for this module (default "{format_adapter}")
- format_adapter: display format for adapters (default "{format_device}")
- format_adapter_separator: show separator if more than one (default " ")
- format_device: display format for devices
- (default "\?if=connected&color=connected {alias}")
- format_device_separator: show separator if more than one (default " ")
- thresholds: specify color thresholds to use
- (default [(False, "bad"), (True, "good")])
-
-Format placeholders:
- {format_adapter} format for adapters
- {adapter} number of adapters, eg 1
-
-format_adapter placeholders:
- {format_device} format for devices
- {device} number of devices, eg 5
- {address} eg, 00:00:00:00:00:00
- {addresstype} eg, public
- {alias} eg, thinkpad
- {class} eg, 123456
- {discoverable} eg, False
- {discoverabletimeout} eg, 0
- {discovering} eg, False
- {modalias} eg, usb:v1D68234ABCDEF5
- {name} eg, z420
- {pairable} eg, True
- {pairabletimeout} eg, 0
- {path} eg, /org/bluez/hci0
- {powered} eg, True
- {uuids} eg, []
-
-format_device placeholders:
- {adapter} eg, /org/bluez/hci0
- {address} eg, 00:00:00:00:00:00
- {addresstype} eg, public
- {alias} eg, MSFT Mouse
- {class} eg, 1234
- {connected} eg, False
- {icon} eg, input-mouse
- {legacypairing} eg, False
- {modalias} eg, usb:v1D68234ABCDEF5
- {name} eg, Microsoft Bluetooth Notebook Mouse 5000
- {paired} eg, True
- {servicesresolved} eg, False
- {trusted} eg, True
- {uuids} eg, []
-
-Color thresholds:
- xxx: print a color based on the value of `xxx` placeholder
-
-Requires:
- pygobject: Python bindings for GObject Introspection
-
-Examples:
-```
-# always display devices
-bluetooth {
- format_device = "\?color=connected {alias}"
-}
-
-# set an alias via blueman-manager or bluetoothctl
-# $ bluetoothctl
-# [bluetooth] # devices
-# [bluetooth] # connect 00:00:00:00:00:00
-# [bluetooth] # set-alias "MSFT Mouse"
-
-# display missing adapter (feat. request)
-bluetooth {
- format = "\?if=adapter {format_adapter}|\?color=darkgray No Adapter"
-}
-
-# legacy default
-bluetooth {
- format = "\?color=good BT: {format_adapter}|\?color=bad BT"
- format_device_separator = "\|"
-}
-```
-
-@author jmdana, lasers
-@license BSD
-
-SAMPLE OUTPUT
-{'color': '#00FF00', 'full_text': u'Microsoft Bluetooth Notebook Mouse 5000'}
-"""
-
-from gi.repository import Gio
-
-
-class Py3status:
- """ """
-
- # available configuration parameters
- cache_timeout = 10
- format = "{format_adapter}"
- format_adapter = "{format_device}"
- format_adapter_separator = " "
- format_device = "\?if=connected&color=connected {alias}"
- format_device_separator = " "
- thresholds = [(False, "bad"), (True, "good")]
-
- def post_config_hook(self):
- bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None)
- iface = "org.freedesktop.DBus.ObjectManager"
- self.bluez_manager = Gio.DBusProxy.new_sync(
- bus, Gio.DBusProxyFlags.NONE, None, "org.bluez", "/", iface, None
- )
-
- self.names_and_matches = [
- ("adapters", "org.bluez.Adapter1"),
- ("devices", "org.bluez.Device1"),
- ]
-
- self.thresholds_init = {}
- for name in ["format", "format_adapter", "format_device"]:
- self.thresholds_init[name] = self.py3.get_color_names_list(
- getattr(self, name)
- )
-
- def _get_bluez_data(self):
- objects = self.bluez_manager.GetManagedObjects()
- temporary = {}
-
- for path, interfaces in sorted(objects.items()):
- interface_keys = interfaces.keys()
- for name, match in self.names_and_matches:
- if match in interface_keys:
- interface = {k.lower(): v for k, v in
interfaces[match].items()}
- interface.update({"path": path, "uuids": []})
- temporary.setdefault(name, []).append(interface)
- break
-
- for device in temporary.pop("devices", []):
- for index, adapter in enumerate(temporary["adapters"]):
- if device["adapter"] == adapter["path"]:
- temporary["adapters"][index].setdefault("devices",
[]).append(
- device
- )
- break
-
- return temporary
-
- def bluetooth2(self):
- bluez_data = self._get_bluez_data()
- adapters = bluez_data.pop("adapters", [])
- new_adapter = []
-
- for adapter in adapters:
- devices = adapter.pop("devices", [])
- new_device = []
-
- for device in devices:
- for x in self.thresholds_init["format_device"]:
- 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)
-
- adapter.update({"format_device": format_device, "device":
len(devices)})
-
- for x in self.thresholds_init["format_adapter"]:
- if x in adapter:
- self.py3.threshold_get_color(adapter[x], x)
-
- new_adapter.append(self.py3.safe_format(self.format_adapter,
adapter))
-
- format_adapter_separator =
self.py3.safe_format(self.format_adapter_separator)
- format_adapter = self.py3.composite_join(format_adapter_separator,
new_adapter)
-
- bluetooth_data = {"format_adapter": format_adapter, "adapter":
len(adapters)}
-
- for x in self.thresholds_init["format"]:
- if x in bluetooth_data:
- self.py3.threshold_get_color(bluetooth_data[x], x)
-
- return {
- "cached_until": self.py3.time_in(self.cache_timeout),
- "full_text": self.py3.safe_format(self.format, bluetooth_data),
- }
-
-
-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.47/py3status/modules/check_tcp.py
new/py3status-3.49/py3status/modules/check_tcp.py
--- old/py3status-3.47/py3status/modules/check_tcp.py 2022-10-02
16:25:48.000000000 +0200
+++ new/py3status-3.49/py3status/modules/check_tcp.py 2023-01-09
18:39:16.000000000 +0100
@@ -44,7 +44,12 @@
def check_tcp(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- result = sock.connect_ex((self.host, self.port))
+
+ try:
+ result = sock.connect_ex((self.host, self.port))
+ except socket.gaierror:
+ sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
+ result = sock.connect_ex((self.host, self.port))
if result:
color = self.color_off
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/py3status/modules/clock.py
new/py3status-3.49/py3status/modules/clock.py
--- old/py3status-3.47/py3status/modules/clock.py 2022-10-02
16:25:48.000000000 +0200
+++ new/py3status-3.49/py3status/modules/clock.py 2022-10-27
10:35:49.000000000 +0200
@@ -6,12 +6,11 @@
Timezones are defined in the `format` using the TZ name in squiggly brackets eg
`{GMT}`, `{Portugal}`, `{Europe/Paris}`, `{America/Argentina/Buenos_Aires}`.
-ISO-3166 two letter country codes eg `{de}` can also be used but if more than
-one timezone exists for the country eg `{us}` the first one will be selected.
+See https://docs.python.org/3/library/zoneinfo.html for supported formats.
`{Local}` can be used for the local settings of your computer.
-Note: Timezones are case sensitive
+Note: Timezones are case sensitive!
A full list of timezones can be found at
https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
@@ -54,10 +53,6 @@
{timezone_unclear} full timezone name eg `America/Argentina/Buenos_Aires`
but is empty if only one timezone is provided
-Requires:
- pytz: cross platform time zone library for python
- tzlocal: tzinfo object for the local timezone
-
Examples:
```
# cycling through London, Warsaw, Tokyo
@@ -80,7 +75,7 @@
}
```
-@author tobes
+@author tobes ultrabug
@license BSD
SAMPLE OUTPUT
@@ -95,8 +90,11 @@
import time
from datetime import datetime
-import pytz
-import tzlocal
+try:
+ import zoneinfo
+# Fall back for python 3.7 and python 3.8
+except ImportError:
+ from backports import zoneinfo
CLOCK_BLOCKS = "ðð§ðððððððððð
ðð¡ðð¢ðð£ðð¤ðð¥ðð¦"
@@ -192,24 +190,13 @@
# special Local timezone
if tz == "Local":
try:
- return tzlocal.get_localzone()
- except pytz.UnknownTimeZoneError:
+ return zoneinfo.ZoneInfo("localtime")
+ except zoneinfo.ZoneInfoNotFoundError:
return "?"
-
- # we can use a country code to get tz
- # FIXME this is broken for multi-timezone countries eg US
- # for now we just grab the first one
- if len(tz) == 2:
- try:
- zones = pytz.country_timezones(tz)
- except KeyError:
- return "?"
- tz = zones[0]
-
# get the timezone
try:
- zone = pytz.timezone(tz)
- except pytz.UnknownTimeZoneError:
+ zone = zoneinfo.ZoneInfo(tz)
+ except zoneinfo.ZoneInfoNotFoundError:
return "?"
return zone
@@ -264,12 +251,7 @@
idx = int(h / self.block_hours * len(self.blocks))
icon = self.blocks[idx]
- try:
- # tzlocal < 3.0
- timezone = zone.zone
- except AttributeError:
- # tzlocal >= 3.0
- timezone = zone.key
+ timezone = zone.key
tzname = timezone.split("/")[-1].replace("_", " ")
if self.multiple_tz:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/py3status/modules/do_not_disturb.py
new/py3status-3.49/py3status/modules/do_not_disturb.py
--- old/py3status-3.47/py3status/modules/do_not_disturb.py 2022-10-02
16:25:48.000000000 +0200
+++ new/py3status-3.49/py3status/modules/do_not_disturb.py 2023-02-17
13:39:22.000000000 +0100
@@ -129,8 +129,18 @@
Mako Notification.
"""
+ # From version mako 1.7 we can use "makoctl mode"
def setup(self, parent):
- self.toggle(parent.state)
+ self.has_makoctl_mode = bool(
+ self.parent.py3.check_commands(["makoctl"])
+ ) and not self.parent.py3.command_run("makoctl mode")
+
+ def get_state(self):
+ if self.has_makoctl_mode:
+ state = self.parent.py3.command_output("makoctl mode")
+ return state.strip() == "do-not-disturb"
+ else:
+ return self.parent.state
def toggle(self, state):
if state is True:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/py3status/modules/google_calendar.py
new/py3status-3.49/py3status/modules/google_calendar.py
--- old/py3status-3.47/py3status/modules/google_calendar.py 2022-10-02
17:08:43.000000000 +0200
+++ new/py3status-3.49/py3status/modules/google_calendar.py 2023-02-17
13:39:22.000000000 +0100
@@ -25,6 +25,8 @@
(default 1)
cache_timeout: How often the module is refreshed in seconds
(default 60)
+ calendar_id: The ID of the calendar to display.
+ (default "primary")
client_secret: the path to your client_secret file which
contains your OAuth 2.0 credentials.
(default '~/.config/py3status/google_calendar.client_secret')
@@ -182,6 +184,7 @@
button_refresh = 2
button_toggle = 1
cache_timeout = 60
+ calendar_id = "primary"
client_secret = "~/.config/py3status/google_calendar.client_secret"
events_within_hours = 12
force_lowercase = False
@@ -284,7 +287,7 @@
eventsResult = (
self.service.events()
.list(
- calendarId="primary",
+ calendarId=self.calendar_id,
timeMax=time_max.isoformat() + "Z", # 'Z' indicates UTC
time
timeMin=time_min.isoformat() + "Z", # 'Z' indicates UTC
time
singleEvents=True,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/py3status/modules/kdeconnector.py
new/py3status-3.49/py3status/modules/kdeconnector.py
--- old/py3status-3.47/py3status/modules/kdeconnector.py 2022-10-02
16:25:48.000000000 +0200
+++ new/py3status-3.49/py3status/modules/kdeconnector.py 2023-01-09
18:39:16.000000000 +0100
@@ -25,6 +25,8 @@
{name} name of the device
{notif_size} number of notifications
{notif_status} shows if a notification is available or not
+ {net_type} shows cell network type
+ {net_strength} shows cell network strength
Color options:
color_bad: Device unknown, unavailable
@@ -40,12 +42,12 @@
```
kdeconnector {
device_id = "aa0844d33ac6ca03"
- format = "{name} {battery} â¡ {state}"
+ format = "{name} {charge} {bat_status}"
low_battery = "10"
}
```
-@author Moritz Lüdecke
+@author Moritz Lüdecke, valdur55
SAMPLE OUTPUT
{'color': '#00FF00', 'full_text': u'Samsung Galaxy S6 \u2709 \u2B06 97%'}
@@ -66,17 +68,24 @@
{'color': '#FF0000', 'full_text': u'unknown device'}
"""
-from pydbus import SessionBus
+import sys
+from threading import Thread
+from dbus.mainloop.glib import DBusGMainLoop
+from gi.repository import GLib
+from pydbus import SessionBus
+STRING_GEVENT = "this module does not work with gevent"
SERVICE_BUS = "org.kde.kdeconnect"
INTERFACE = SERVICE_BUS + ".device"
INTERFACE_DAEMON = SERVICE_BUS + ".daemon"
INTERFACE_BATTERY = INTERFACE + ".battery"
INTERFACE_NOTIFICATIONS = INTERFACE + ".notifications"
+INTERFACE_CONN_REPORT = INTERFACE + ".connectivity_report"
PATH = "/modules/kdeconnect"
DEVICE_PATH = PATH + "/devices"
BATTERY_SUBPATH = "/battery"
+CONN_REPORT_SUBPATH = "/connectivity_report"
NOTIFICATIONS_SUBPATH = "/notifications"
UNKNOWN = "Unknown"
UNKNOWN_DEVICE = "unknown device"
@@ -100,52 +109,213 @@
status_notif = " â"
def post_config_hook(self):
+ if self.py3.is_gevent():
+ raise Exception(STRING_GEVENT)
+
self._bat = None
+ self._con = None
self._dev = None
self._not = None
+ self._result = {}
+
+ self._signal_reachable_changed = None
+ self._signal_battery = None
+ self._signal_notifications = None
+ self._signal_conn_report = None
+
+ self._format_contains_notifications = self.py3.format_contains(
+ self.format, ["notif_size", "notif_status"]
+ )
+
+ self._format_contains_connection_status = self.py3.format_contains(
+ self.format, ["net_type", "net_strength"]
+ )
+
+ # start last
+ self._kill = False
+ self._dbus_loop = DBusGMainLoop()
+ self._dbus = SessionBus()
+ self._bus_initialized = self._init_dbus()
+ self._start_listener()
+
+ if self._bus_initialized:
+ self._update_conn_info()
+ self._update_notif_info()
+ self._update_battery_info()
+
+ def _start_loop(self):
+ self._loop = GLib.MainLoop()
+ GLib.timeout_add(1000, self._timeout)
+ try:
+ self._loop.run()
+ except KeyboardInterrupt:
+ # This branch is only needed for the test mode
+ self._kill = True
+
+ def _start_listener(self):
+ self._signal_reachable_changed = self._dbus.con.signal_subscribe(
+ sender=None,
+ interface_name=INTERFACE,
+ member="reachableChanged",
+ object_path=None,
+ arg0=None,
+ flags=0,
+ callback=self._reachable_on_change,
+ )
+
+ self._signal_battery = self._dbus.con.signal_subscribe(
+ sender=None,
+ interface_name=INTERFACE_BATTERY,
+ member=None,
+ object_path=None,
+ arg0=None,
+ flags=0,
+ callback=self._battery_on_change,
+ )
+
+ if self._format_contains_notifications:
+ self._signal_notifications = self._dbus.con.signal_subscribe(
+ sender=None,
+ interface_name=INTERFACE_NOTIFICATIONS,
+ member=None,
+ object_path=None,
+ arg0=None,
+ flags=0,
+ callback=self._notifications_on_change,
+ )
+
+ if self._format_contains_connection_status:
+ self._signal_conn_report = self._dbus.con.signal_subscribe(
+ sender=None,
+ interface_name=INTERFACE_CONN_REPORT,
+ member=None,
+ object_path=None,
+ arg0=None,
+ flags=0,
+ callback=self._conn_report_on_change,
+ )
+
+ t = Thread(target=self._start_loop)
+ t.daemon = True
+ t.start()
+
+ def _notifications_on_change(
+ self, connection, owner, object_path, interface_name, event, new_value
+ ):
+ if self._is_current_device(object_path):
+ self._update_notif_info()
+ self.py3.update()
+
+ def _reachable_on_change(
+ self, connection, owner, object_path, interface_name, event, new_value
+ ):
+ if self._is_current_device(object_path):
+ # Update only when device is connected
+ if new_value[0]:
+ self._update_battery_info()
+ self._update_notif_info()
+ self._update_conn_info()
+ self.py3.update()
+
+ def _battery_on_change(
+ self, connection, owner, object_path, interface_name, event, new_value
+ ):
+ if self._is_current_device(object_path):
+ if event == "refreshed":
+ if new_value[1] != -1:
+ self._set_battery_status(
+ isCharging=new_value[0], charge=new_value[1]
+ )
+ elif event == "stateChanged":
+ self._set_battery_status(isCharging=new_value[0], charge=None)
+ elif event == "chargeChanged":
+ self._set_battery_status(isCharging=None, charge=new_value[0])
+ else:
+ self._update_battery_info()
+ self.py3.update()
+
+ def _conn_report_on_change(
+ self, connection, owner, object_path, interface_name, event, new_value
+ ):
+ if self._is_current_device(object_path):
+ if event == "refreshed":
+ if (
+ self._result["net_type"] != new_value[0]
+ or self._result["net_strength_raw"] != new_value[1]
+ ):
+ self._set_conn_status(
+ net_type=new_value[0], net_strength=new_value[1]
+ )
+ self.py3.update()
+ else:
+ self._update_conn_info()
+ self.py3.update()
+
+ def _is_current_device(self, object_path):
+ return self.device_id in object_path
+
+ def _timeout(self):
+ if self._kill:
+ self._loop.quit()
+ sys.exit(0)
+
def _init_dbus(self):
"""
Get the device id
"""
- _bus = SessionBus()
-
if self.device_id is None:
- self.device_id = self._get_device_id(_bus)
+ self.device_id = self._get_device_id()
if self.device_id is None:
return False
try:
- self._dev = _bus.get(SERVICE_BUS, DEVICE_PATH +
f"/{self.device_id}")
+ self._dev = self._dbus.get(SERVICE_BUS, DEVICE_PATH +
f"/{self.device_id}")
try:
- self._bat = _bus.get(
+ self._bat = self._dbus.get(
SERVICE_BUS, DEVICE_PATH + f"/{self.device_id}" +
BATTERY_SUBPATH
)
- self._not = _bus.get(
- SERVICE_BUS,
- DEVICE_PATH + f"/{self.device_id}" + NOTIFICATIONS_SUBPATH,
- )
+
+ if self._format_contains_notifications:
+ self._not = self._dbus.get(
+ SERVICE_BUS,
+ DEVICE_PATH + f"/{self.device_id}" +
NOTIFICATIONS_SUBPATH,
+ )
+ else:
+ self._not = None
except Exception:
# Fallback to the old version
self._bat = None
self._not = None
+
+ try: # This plugin is released after kdeconnect version Mar 13,
2021
+ if self._format_contains_connection_status:
+ self._con = self._dbus.get(
+ SERVICE_BUS,
+ DEVICE_PATH + f"/{self.device_id}" +
CONN_REPORT_SUBPATH,
+ )
+ else:
+ self._con = None
+ except Exception:
+ self._con = None
+
except Exception:
return False
return True
- def _get_device_id(self, bus):
+ def _get_device_id(self):
"""
Find the device id
"""
- _dbus = bus.get(SERVICE_BUS, PATH)
- devices = _dbus.devices()
+ _bus = self._dbus.get(SERVICE_BUS, PATH)
+ devices = _bus.devices()
if self.device is None and self.device_id is None and len(devices) ==
1:
return devices[0]
for id in devices:
- self._dev = bus.get(SERVICE_BUS, DEVICE_PATH + f"/{id}")
+ self._dev = self._dbus.get(SERVICE_BUS, DEVICE_PATH + f"/{id}")
if self.device == self._dev.name:
return id
@@ -196,58 +366,105 @@
"isCharging": isCharging == 1,
}
except Exception:
- return None
+ return {
+ "charge": -1,
+ "isCharging": None,
+ }
return battery
+ def _get_conn(self):
+ """
+ Get the connection report
+ """
+ try:
+ if self._con:
+ # Possible values are -1 - 4
+ strength = self._con.cellularNetworkStrength
+ type = self._con.cellularNetworkType
+
+ con_info = {
+ "strength": strength,
+ "type": type,
+ }
+ else:
+ con_info = {
+ "strength": -1,
+ "type": "",
+ }
+ except Exception:
+ return {
+ "strength": -1,
+ "type": "",
+ }
+
+ return con_info
+
def _get_notifications(self):
"""
Get notifications
"""
try:
if self._not:
- notifications = {"activeNotifications":
self._not.activeNotifications()}
+ notifications = self._not.activeNotifications()
else:
- notifications = {"activeNotifications":
self._dev.activeNotifications()}
- notifications = {"activeNotifications": notifications}
+ notifications = self._dev.activeNotifications()
except Exception:
- return None
+ return []
return notifications
- def _get_battery_status(self, battery):
+ def _set_battery_status(self, isCharging, charge):
"""
Get the battery status
"""
- if not battery or battery["charge"] == -1:
- return (UNKNOWN_SYMBOL, UNKNOWN, "#FFFFFF")
-
- if battery["isCharging"]:
- status = self.status_chr
- color = self.py3.COLOR_GOOD
- else:
- status = self.status_bat
- color = self.py3.COLOR_DEGRADED
-
- if not battery["isCharging"] and battery["charge"] <=
self.low_threshold:
- color = self.py3.COLOR_BAD
-
- if battery["charge"] > 99:
- status = self.status_full
+ if charge == -1:
+ self._result["charge"] = UNKNOWN_SYMBOL
+ self._result["bat_status"] = UNKNOWN
+ self._result["color"] = "#FFFFFF"
+ return
+
+ if charge is not None:
+ self._result["charge"] = charge
+
+ if isCharging is not None:
+ if isCharging:
+ self._result["bat_status"] = self.status_chr
+ self._result["color"] = self.py3.COLOR_GOOD
+ else:
+ self._result["bat_status"] = self.status_bat
+ self._result["color"] = self.py3.COLOR_DEGRADED
- return (battery["charge"], status, color)
+ if (
+ not isCharging
+ and isinstance(self._result["charge"], int)
+ and self._result["charge"] <= self.low_threshold
+ ):
+ self._result["color"] = self.py3.COLOR_BAD
+
+ if charge is not None:
+ if charge > 99:
+ self._result["bat_status"] = self.status_full
- def _get_notifications_status(self, notifications):
+ def _set_notifications_status(self, activeNotifications):
"""
Get the notifications status
"""
- if notifications:
- size = len(notifications["activeNotifications"])
- else:
- size = 0
- status = self.status_notif if size > 0 else self.status_no_notif
+ size = len(activeNotifications)
+ self._result["notif_status"] = (
+ self.status_notif if size > 0 else self.status_no_notif
+ )
+ self._result["notif_size"] = size
- return (size, status)
+ def _set_conn_status(self, net_type, net_strength):
+ """
+ Get the conn status
+ """
+ self._result["net_strength_raw"] = net_strength
+ self._result["net_strength"] = (
+ net_strength * 25 if net_strength > -1 else UNKNOWN_SYMBOL
+ )
+ self._result["net_type"] = net_type
def _get_text(self):
"""
@@ -265,38 +482,68 @@
self.py3.COLOR_BAD,
)
- battery = self._get_battery()
- (charge, bat_status, color) = self._get_battery_status(battery)
-
- notif = self._get_notifications()
- (notif_size, notif_status) = self._get_notifications_status(notif)
-
return (
self.py3.safe_format(
self.format,
- dict(
- name=device["name"],
- charge=charge,
- bat_status=bat_status,
- notif_size=notif_size,
- notif_status=notif_status,
- ),
+ dict(name=device["name"], **self._result),
),
- color,
+ self._result.get("color"),
+ )
+
+ def _update_conn_info(self):
+ if self._format_contains_connection_status:
+ conn = self._get_conn()
+ self._set_conn_status(net_type=conn["type"],
net_strength=conn["strength"])
+
+ def _update_notif_info(self):
+ if self._format_contains_notifications:
+ notif = self._get_notifications()
+ self._set_notifications_status(notif)
+
+ def _update_battery_info(self):
+ battery = self._get_battery()
+ self._set_battery_status(
+ isCharging=battery["isCharging"], charge=battery["charge"]
)
+ def kill(self):
+ self._kill = True
+ if self._signal_reachable_changed:
+ self._dbus.con.signal_unsubscribe(self._signal_reachable_changed)
+
+ if self._signal_battery:
+ self._dbus.con.signal_unsubscribe(self._signal_battery)
+
+ if self._signal_notifications:
+ self._dbus.con.signal_unsubscribe(self._signal_notifications)
+
+ if self._signal_conn_report:
+ self._dbus.con.signal_unsubscribe(self._signal_conn_report)
+
def kdeconnector(self):
"""
Get the current state and return it.
"""
- if self._init_dbus():
+ if self._kill:
+ raise KeyboardInterrupt
+
+ if self._bus_initialized:
(text, color) = self._get_text()
+ cached_until = self.py3.CACHE_FOREVER
+
else:
text = UNKNOWN_DEVICE
color = self.py3.COLOR_BAD
+ cached_until = self.py3.time_in(self.cache_timeout)
+ self._bus_initialized = self._init_dbus()
+ if self._bus_initialized:
+ self._update_conn_info()
+ self._update_notif_info()
+ self._update_battery_info()
+ self.py3.update()
response = {
- "cached_until": self.py3.time_in(self.cache_timeout),
+ "cached_until": cached_until,
"full_text": text,
"color": color,
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/py3status/modules/mpris.py
new/py3status-3.49/py3status/modules/mpris.py
--- old/py3status-3.47/py3status/modules/mpris.py 2022-10-02
15:59:23.000000000 +0200
+++ new/py3status-3.49/py3status/modules/mpris.py 2023-01-09
18:39:16.000000000 +0100
@@ -668,7 +668,7 @@
def kill(self):
self._kill = True
if self._name_owner_change_match:
-
self.parent._dbus._clean_up_signal_match(self._name_owner_change_match)
+ self._dbus._clean_up_signal_match(self._name_owner_change_match)
def mpris(self):
"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/py3status/modules/timewarrior.py
new/py3status-3.49/py3status/modules/timewarrior.py
--- old/py3status-3.47/py3status/modules/timewarrior.py 2021-08-30
10:15:50.000000000 +0200
+++ new/py3status-3.49/py3status/modules/timewarrior.py 2022-11-20
12:12:25.000000000 +0100
@@ -140,7 +140,6 @@
from json import loads as json_loads
import datetime as dt
-from dateutil.relativedelta import relativedelta
STRING_NOT_INSTALLED = "not installed"
DATETIME = "%Y%m%dT%H%M%SZ"
@@ -244,15 +243,15 @@
end = dt.datetime.strptime(time["end"], DATETIME)
start = dt.datetime.strptime(time["start"], DATETIME)
- duration = relativedelta(end, start)
+ duration = end - start
time["format_duration"] = self.py3.safe_format(
self.format_duration,
{
"days": duration.days,
- "hours": duration.hours,
- "minutes": duration.minutes,
- "seconds": duration.seconds,
+ "hours": duration.seconds // (60 * 60),
+ "minutes": (duration.seconds // 60) % 60,
+ "seconds": duration.seconds % 60,
},
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/py3status/modules/volume_status.py
new/py3status-3.49/py3status/modules/volume_status.py
--- old/py3status-3.47/py3status/modules/volume_status.py 2022-10-02
16:25:48.000000000 +0200
+++ new/py3status-3.49/py3status/modules/volume_status.py 2023-01-10
13:37:26.000000000 +0100
@@ -26,10 +26,6 @@
(default False)
max_volume: Allow the volume to be increased past 100% if available.
pactl and pamixer supports this. (default 120)
- start_delay: Number of seconds to wait before starting this module.
- This allows some systems to start the audio backend before we
- try picking it up.
- (default 0)
thresholds: Threshold for percent volume.
(default [(0, 'bad'), (20, 'degraded'), (50, 'good')])
volume_delta: Percentage amount that the volume is increased or
@@ -118,13 +114,13 @@
def setup(self, parent):
if self.card is None:
self.card = "0"
+ if self.device is None:
+ self.device = "default"
if self.channel is None:
controls = self.parent.py3.command_output(
- ["amixer", "scontrols"]
+ ["amixer", "-c", self.card, "-D", self.device, "scontrols"]
).splitlines()
self.channel =
controls[-abs(int(self.is_input))].split("'")[1::2][0]
- if self.device is None:
- self.device = "default"
self.cmd = [
"amixer",
"-M",
@@ -332,7 +328,6 @@
format_muted = r"[\?if=is_input ð¶|âª]: muted"
is_input = False
max_volume = 120
- start_delay = 0
thresholds = [(0, "bad"), (20, "degraded"), (50, "good")]
volume_delta = 5
@@ -358,12 +353,14 @@
"param": "threshold_degraded",
"msg": "obsolete set using thresholds parameter",
},
+ {
+ "param": "start_delay",
+ "msg": "obsolete parameter",
+ },
],
}
def post_config_hook(self):
- if self.start_delay:
- sleep(int(self.start_delay))
if not self.command:
commands = ["pamixer", "pactl", "amixer"]
# pamixer, pactl requires pulseaudio to work
@@ -383,9 +380,21 @@
if self.device is not None:
self.device = str(self.device)
- self.backend = globals()[self.command.capitalize()](self)
+ self._init_backend()
self.color_muted = self.py3.COLOR_MUTED or self.py3.COLOR_BAD
+ def _init_backend(self):
+ # attempt it a few times since the audio service may still be loading
during startup
+ for i in range(6):
+ try:
+ self.backend = globals()[self.command.capitalize()](self)
+ return
+ except Exception: # noqa e722
+ # try again later (exponential backoff)
+ sleep(0.5 * 2**i)
+
+ self.backend = globals()[self.command.capitalize()](self)
+
def volume_status(self):
perc, muted = self.backend.get_volume()
color = None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/py3status/modules/window.py
new/py3status-3.49/py3status/modules/window.py
--- old/py3status-3.47/py3status/modules/window.py 2022-10-02
16:25:48.000000000 +0200
+++ new/py3status-3.49/py3status/modules/window.py 2022-10-05
17:35:50.000000000 +0200
@@ -45,10 +45,12 @@
def compatibility(self, window_properties):
# specify width to truncate title with ellipsis
- if self.parent.max_width:
- title = window_properties["title"]
- if title and len(title) > self.parent.max_width:
+ title = window_properties.get("title", "")
+ if title:
+ if self.parent.max_width and len(title) > self.parent.max_width:
window_properties["title"] = title[: self.parent.max_width -
1] + "â¦"
+ else:
+ window_properties["title"] = ""
return window_properties
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/py3status/version.py
new/py3status-3.49/py3status/version.py
--- old/py3status-3.47/py3status/version.py 2022-10-02 17:50:36.000000000
+0200
+++ new/py3status-3.49/py3status/version.py 2023-02-17 13:40:42.000000000
+0100
@@ -1 +1 @@
-version = "3.47"
+version = "3.49"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/py3status.egg-info/PKG-INFO
new/py3status-3.49/py3status.egg-info/PKG-INFO
--- old/py3status-3.47/py3status.egg-info/PKG-INFO 2022-10-02
17:54:02.000000000 +0200
+++ new/py3status-3.49/py3status.egg-info/PKG-INFO 2023-02-17
13:41:23.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: py3status
-Version: 3.47
+Version: 3.49
Summary: py3status: an extensible i3status wrapper written in python
Home-page: https://github.com/ultrabug/py3status
Author: Ultrabug
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/py3status.egg-info/SOURCES.txt
new/py3status-3.49/py3status.egg-info/SOURCES.txt
--- old/py3status-3.47/py3status.egg-info/SOURCES.txt 2022-10-02
17:54:02.000000000 +0200
+++ new/py3status-3.49/py3status.egg-info/SOURCES.txt 2023-02-17
13:41:23.000000000 +0100
@@ -57,7 +57,6 @@
py3status/modules/backlight.py
py3status/modules/battery_level.py
py3status/modules/bluetooth.py
-py3status/modules/bluetooth2.py
py3status/modules/check_tcp.py
py3status/modules/clementine.py
py3status/modules/clock.py
@@ -166,5 +165,6 @@
tests/test_consistency.py
tests/test_formatter.py
tests/test_module_doc.py
+tests/test_module_load.py
tests/test_py3.py
tests/test_user_modules.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/tests/test_module_load.py
new/py3status-3.49/tests/test_module_load.py
--- old/py3status-3.47/tests/test_module_load.py 1970-01-01
01:00:00.000000000 +0100
+++ new/py3status-3.49/tests/test_module_load.py 2023-01-09
18:39:16.000000000 +0100
@@ -0,0 +1,45 @@
+from py3status.module_test import MockPy3statusWrapper
+from py3status.module import Module
+
+
+class TestModule:
+ static_variable = 123
+
+ def __init__(self):
+ self.instance_variable = 321
+
+ def post_config_hook(self):
+ pass
+
+ @staticmethod
+ def static_method(self):
+ raise Exception("I don't want to be called!")
+
+ @property
+ def property(self):
+ raise Exception("I don't want to be called!")
+
+ def instance_method(self):
+ raise Exception("I don't want to be called!")
+
+ def _private_instance_method(self):
+ raise Exception("I don't want to be called!")
+
+ def on_click(self, event):
+ raise Exception("I don't want to be called!")
+
+
+def test_module_load():
+ mock = MockPy3statusWrapper(
+ {
+ "general": {},
+ "py3status": {},
+ ".module_groups": {},
+ "test_module": {},
+ }
+ )
+
+ module = TestModule()
+ m = Module("test_module", {}, mock, module)
+ m.prepare_module()
+ assert list(m.methods) == ["instance_method"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py3status-3.47/tox.ini new/py3status-3.49/tox.ini
--- old/py3status-3.47/tox.ini 2022-08-25 16:23:38.000000000 +0200
+++ new/py3status-3.49/tox.ini 2022-12-12 08:07:52.000000000 +0100
@@ -1,5 +1,5 @@
[tox]
-envlist = py37, py38, py39, py310, mypy
+envlist = py37, py38, py39, py310, py311, mypy
skip_missing_interpreters = True
[testenv]
@@ -29,6 +29,7 @@
[gh-actions]
python =
3.7: py37
- 3.8: py38, mypy
- 3.9: py39
+ 3.8: py38
+ 3.9: py39, mypy
3.10: py310
+ 3.11: py311