fix(mpris): keep the service importable without dbus-next

The stub dbus_property() returned a bare function, so the read/write
properties (@Volume.setter and friends) raised AttributeError at import
time. That made any host without dbus-next -- macOS, Windows, minimal
containers -- crash before the TUI could start, because app.py imports
this module unconditionally.

Replace the stub with a descriptor that supports .getter()/.setter(), and
give the service a short label for the status bar.
This commit is contained in:
beefcarver committed 2026-10-30 18:42:50 -04:00
1 parent 876057bf68
commit d83a9ef03d
1 file changed
+35 -2
+35 -2
View File
@@ -44,9 +44,39 @@ except Exception: # pragma: no cover
def emit_properties_changed(self, *args: Any, **kwargs: Any) -> None:
return None
class _StubProperty: # type: ignore[no-redef]
"""Stand-in for ``dbus_next.service.dbus_property`` on D-Bus-less hosts.
It has to behave like a descriptor that also supports ``.setter()``,
because the interfaces below define read/write properties with the
usual decorator idiom. Importing this module must never fail just
because there is no session bus (macOS, Windows, minimal containers).
"""
def __init__(self, fget: Any = None) -> None:
self.fget = fget
self.fset: Any = None
def getter(self, fget: Any) -> "_StubProperty":
self.fget = fget
return self
def setter(self, fset: Any) -> "_StubProperty":
self.fset = fset
return self
def __get__(self, obj: Any, objtype: Any = None) -> Any:
if obj is None or self.fget is None:
return self
return self.fget(obj)
def __set__(self, obj: Any, value: Any) -> None:
if self.fset is not None:
self.fset(obj, value)
def dbus_property(*args: Any, **kwargs: Any): # type: ignore[no-redef]
def decorator(function):
return function
def decorator(function: Any) -> _StubProperty:
return _StubProperty(function)
return decorator
@@ -254,6 +284,9 @@ class _PlayerInterface(ServiceInterface):
class MprisService:
#: Status-bar name for this backend (see :mod:`somafm_tui.mediasession`).
label = "mpris"
def __init__(
self, actions: "queue.Queue[str]", enabled: bool = True
) -> None: