# SPDX-License-Identifier: MIT # # # This file is formatted with Python Black from dbusmock import DBusMockObject from typing import Dict, Any, NamedTuple, Optional from itertools import count from gi.repository import GLib # type: ignore import dbus import dbus.service import logging ASVType = Dict[str, Any] logging.basicConfig(format="%(levelname).1s|%(name)s: %(message)s", level=logging.DEBUG) logger = logging.getLogger("templates") class MockParams: """ Helper class for storing template parameters. The Mock object passed into ``load()`` is shared between all templates. This makes it easy to have per-template parameters by calling: >>> params = MockParams.get(mock, MAIN_IFACE) >>> params.version = 1 and later, inside a DBus method: >>> params = MockParams.get(self, MAIN_IFACE) >>> return params.version """ @classmethod def get(cls, mock, interface_name): params = getattr(mock, "params", {}) try: return params[interface_name] except KeyError: c = cls() params[interface_name] = c mock.params = params return c class Response(NamedTuple): response: int results: ASVType class Request: _token_counter = count() def __init__( self, bus_name: dbus.service.BusName, sender: str, options: Optional[ASVType] ): options = options or {} sender_token = sender.removeprefix(":").replace(".", "_") handle_token = options.get("handle_token", next(self._token_counter)) self.sender = sender self.handle = ( f"/org/freedesktop/portal/desktop/request/{sender_token}/{handle_token}" ) self.mock = DBusMockObject( bus_name=bus_name, path=self.handle, interface="org.freedesktop.portal.Request", props={}, ) self.mock.AddMethod("", "Close", "", "", "self.RemoveObject(self.path)") logger.debug(f"Request created at {self.handle}") def respond(self, response: Response, delay: int = 0): def respond(): logger.debug(f"Request.Response on {self.handle}: {response}") self.mock.EmitSignalDetailed( "", "Response", "ua{sv}", [dbus.UInt32(response.response), response.results], details={"destination": self.sender}, ) if delay > 0: GLib.timeout_add(delay, respond) else: respond() class Session: _token_counter = count() def __init__( self, bus_name: dbus.service.BusName, sender: str, options: Optional[ASVType] ): options = options or {} sender_token = sender.removeprefix(":").replace(".", "_") handle_token = options.get("session_handle_token", next(self._token_counter)) self.sender = sender self.handle = ( f"/org/freedesktop/portal/desktop/session/{sender_token}/{handle_token}" ) self.mock = DBusMockObject( bus_name=bus_name, path=self.handle, interface="org.freedesktop.portal.Session", props={}, ) self.mock.AddMethod("", "Close", "", "", "self.RemoveObject(self.path)") logger.debug(f"Session created at {self.handle}") def close(self, details: ASVType, delay: int = 0): def respond(): logger.debug(f"Session.Closed on {self.handle}: {details}") self.mock.EmitSignalDetailed( "", "Closed", "a{sv}", [details], destination=self.sender ) if delay > 0: GLib.timeout_add(delay, respond) else: respond()