plusdeck.dbus.domain

DBus uses a collection of types that are documented in the specification. The base types are more fine-grained than Python's base types, but are non-nullable - ie, there's no None type in DBus. Moreover, its collection types don't map cleanly to arbitrary Python class instances - rather, you get basic structs (which correspond to Python tuples) and arrays (which correspond to Python lists). This means that, when interacting with the DBus client, you will need to work with types other than the domain objects used in the standard plusdeck client.

To facilitate this, plusdeck includes a submodule for mapping between domain objects and DBus types, at plusdeck.dbus.domain. This module exports both aliases for the types used by the DBus interface, and mapper classes for packing and unpacking domain objects to and from DBus types.

Represent entities in the plusdeck domain model with dbus-compatible types, and map between the plusdeck and dbus domains.

While these classes don't all implement the same protocols, they do follow a number of important conventions.

Naming Conventions

In general classes corresponding to entities share their names, but with a postfix naming convention.

Dbus types corresponding to entities in the plusdeck domain have T appended to them. For instance, the dbus type corresponding to Optional[float] is OptFloatT, which corresponds to the "d" dbus type signature. This applies to more complex entities as well - for instance, the dbus type corresponding to the Config object is ConfigT.

Mappers - classes that map between entities and dbus types - have M appended to their names. For intance, the mapper for Optional[float] and OptFloatT is called OptFloatM.

pack methods and none properties

Mappers which support it have a pack class method, which takes objects from the plusdeck domain and converts them into dbus data types. For instance, OptFloatM packs an Optional[float] value into a OptFloatT.

Additionally, mappers representing optional data have a property called none, which contains the value that the dbus client canonically interprets as None. For instance, TimeoutM.none is equal to -1.0. Note that, in this case, the dbus client treats any value less than 0 as None.

As a user, you would typically use these APIs when constructing arguments for the dbus client. For example, if you were to call dbus_client.wait_for, it would look like this:

ok: bool = await client.wait_for(StateM.pack(state), TimeoutM.pack(timeout))

unpack methods

Dbus client methods will not only be called with dbus-compatible types, but will return dbus-compatible types as well. Sometimes these are sensible - in fact, most methods return None. However, for dbus-based subscriptions, you may want to unpack the emitted state. For example:


async for st in client.state:
    print(StateM.unpack(st))

ConfigM

Map Config to and from ConfigT (Tuple[Optional[str], str]).

Source code in plusdeck/dbus/domain.py
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
class ConfigM:
    """
    Map `Config` to and from `ConfigT`
    (`Tuple[Optional[str], str]`).
    """

    t: ClassVar[str] = struct(FileM, PortM)

    @staticmethod
    def pack(config: Config) -> ConfigT:
        """
        Pack `Config` to `ConfigT`.
        """

        return (FileM.pack(config.file), config.port)

    @staticmethod
    def unpack(config: ConfigT) -> Config:
        """
        Unpack `ConfigT` to `Config`.
        """

        file, port = config

        return cast(Any, Config)(file=file, port=port)

pack(config) staticmethod

Pack Config to ConfigT.

Source code in plusdeck/dbus/domain.py
183
184
185
186
187
188
189
@staticmethod
def pack(config: Config) -> ConfigT:
    """
    Pack `Config` to `ConfigT`.
    """

    return (FileM.pack(config.file), config.port)

unpack(config) staticmethod

Unpack ConfigT to Config.

Source code in plusdeck/dbus/domain.py
191
192
193
194
195
196
197
198
199
@staticmethod
def unpack(config: ConfigT) -> Config:
    """
    Unpack `ConfigT` to `Config`.
    """

    file, port = config

    return cast(Any, Config)(file=file, port=port)

OptFloatM

Map Optional[float] to and from OptFloatT (float), where float values are expected to be positive.

None values are represented by negative values, namely -1.0.

Source code in plusdeck/dbus/domain.py
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
class OptFloatM:
    """
    Map `Optional[float]` to and from `OptFloatT` (`float`), where float values
    are expected to be positive.

    None values are represented by negative values, namely `-1.0`.
    """

    t: ClassVar[str] = "d"
    none: ClassVar[OptFloatT] = -1.0

    @classmethod
    def pack(cls: Type[Self], t: Optional[float]) -> OptFloatT:
        """
        Pack `Optional[float]` to `OptFloatT`.
        """

        return t if t is not None else cls.none

    @staticmethod
    def unpack(t: OptFloatT) -> Optional[float]:
        """
        Unpack `OptFloatT` to `Optional[float]`.
        """

        return t if t >= 0 else None

pack(t) classmethod

Pack Optional[float] to OptFloatT.

Source code in plusdeck/dbus/domain.py
 96
 97
 98
 99
100
101
102
@classmethod
def pack(cls: Type[Self], t: Optional[float]) -> OptFloatT:
    """
    Pack `Optional[float]` to `OptFloatT`.
    """

    return t if t is not None else cls.none

unpack(t) staticmethod

Unpack OptFloatT to Optional[float].

Source code in plusdeck/dbus/domain.py
104
105
106
107
108
109
110
@staticmethod
def unpack(t: OptFloatT) -> Optional[float]:
    """
    Unpack `OptFloatT` to `Optional[float]`.
    """

    return t if t >= 0 else None

OptStrM

Map Optional[str] to and from StrT (str).

None values are represented by an empty string.

Source code in plusdeck/dbus/domain.py
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
class OptStrM:
    """
    Map `Optional[str]` to and from `StrT` (`str`).

    None values are represented by an empty string.
    """

    t: ClassVar[str] = "s"
    none: ClassVar[str] = ""

    @classmethod
    def pack(cls: Type[Self], string: Optional[str]) -> OptStrT:
        """
        Pack `Optional[str]` to `OptStrT`.
        """

        return string or cls.none

    @classmethod
    def unpack(cls: Type[Self], string: OptStrT) -> Optional[str]:
        """
        Unpack `OptStrT` to `Optional[str]`.
        """

        return string if string != cls.none else None

pack(string) classmethod

Pack Optional[str] to OptStrT.

Source code in plusdeck/dbus/domain.py
126
127
128
129
130
131
132
@classmethod
def pack(cls: Type[Self], string: Optional[str]) -> OptStrT:
    """
    Pack `Optional[str]` to `OptStrT`.
    """

    return string or cls.none

unpack(string) classmethod

Unpack OptStrT to Optional[str].

Source code in plusdeck/dbus/domain.py
134
135
136
137
138
139
140
@classmethod
def unpack(cls: Type[Self], string: OptStrT) -> Optional[str]:
    """
    Unpack `OptStrT` to `Optional[str]`.
    """

    return string if string != cls.none else None

StateM

Map State to and from StateT (str).

Source code in plusdeck/dbus/domain.py
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
class StateM:
    """
    Map `State` to and from `StateT` (`str`).
    """

    t: ClassVar[str] = "s"

    @staticmethod
    def pack(state: State) -> StateT:
        """
        Pack `State` to `StateT`.
        """

        return state.name

    @staticmethod
    def unpack(state: StateT) -> State:
        """
        Unpack `StateT` to `State`.
        """

        return State[state]

pack(state) staticmethod

Pack State to StateT.

Source code in plusdeck/dbus/domain.py
212
213
214
215
216
217
218
@staticmethod
def pack(state: State) -> StateT:
    """
    Pack `State` to `StateT`.
    """

    return state.name

unpack(state) staticmethod

Unpack StateT to State.

Source code in plusdeck/dbus/domain.py
220
221
222
223
224
225
226
@staticmethod
def unpack(state: StateT) -> State:
    """
    Unpack `StateT` to `State`.
    """

    return State[state]

TimeoutM

Bases: OptFloatM

Map Optional[float] to and from TimeoutT (float).

TimeoutM is an alias for OptFloatM.

Source code in plusdeck/dbus/domain.py
146
147
148
149
150
151
152
153
154
class TimeoutM(OptFloatM):
    """
    Map `Optional[float]` to and from `TimeoutT` (`float`).

    `TimeoutM` is an alias for `OptFloatM`.
    """

    t: ClassVar[str] = OptFloatM.t
    none: ClassVar[float] = OptFloatM.none