-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathcommon.py
More file actions
133 lines (91 loc) · 4.76 KB
/
common.py
File metadata and controls
133 lines (91 loc) · 4.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
from __future__ import annotations
from abc import ABC
from typing import Annotated, Generic, Literal, NamedTuple, Optional, Union
from pydantic import Field, JsonValue
from typing_extensions import TypedDict, TypeVar
from streamdeck.models.events.base import ConfiguredBaseModel
## Mixin classes for common event model fields.
class ContextualEventMixin:
"""Mixin class for event models that have action and context fields."""
action: str
"""Unique identifier of the action"""
context: str
"""Identifies the instance of an action that caused the event, i.e. the specific key or dial."""
class DeviceSpecificEventMixin:
"""Mixin class for event models that have a device field."""
device: str
"""Unique identifier of the Stream Deck device that this event is associated with."""
## Payload models and metadata used by multiple event models.
PluginDefinedData = dict[str, JsonValue]
"""Data of arbitrary structure that is defined in and relevant to the plugin.
The root of the data structure will always be a dict of string keys, while the values can be any JSON-compatible type.
"""
EncoderControllerType = Literal["Encoder"]
"""The 'Encoder' controller type refers to a dial or touchscreen on a 'Stream Deck +' device."""
KeypadControllerType = Literal["Keypad"]
"""The 'Keypad' controller type refers to a standard action on a Stream Deck device, e.g. buttons or a pedal."""
ControllerType = Literal[EncoderControllerType, KeypadControllerType]
"""Defines the controller type the action is applicable to."""
CT = TypeVar("CT", bound=ControllerType, default=ControllerType)
class BasePayload(ConfiguredBaseModel, Generic[CT], ABC):
"""Base class for all complex payload models."""
controller: CT
"""Defines the controller type the action is applicable to.
'Keypad' refers to a standard action on a Stream Deck device, e.g. buttons or a pedal.
'Encoder' refers to a dial / touchscreen on a 'Stream Deck +' device.
"""
settings: PluginDefinedData
"""Settings associated with the action instance."""
class CoordinatesDict(TypedDict):
"""Coordinates that identify the location of an action."""
column: int
"""Column the action instance is located in, indexed from 0."""
row: int
"""Row the action instance is located on, indexed from 0.
When the device is DeviceType.StreamDeckPlus the row can be 0 for keys (Keypad),
and will always be 0 for dials (Encoder).
"""
class Coordinates(NamedTuple):
"""Coordinates that identify the location of an action."""
column: int
"""Column the action instance is located in, indexed from 0."""
row: int
"""Row the action instance is located on, indexed from 0.
When the device is DeviceType.StreamDeckPlus the row can be 0 for keys (Keypad),
and will always be 0 for dials (Encoder).
"""
class CoordinatesPayloadMixin:
"""Mixin class for event models that have a coordinates field."""
coordinates_obj: Annotated[
CoordinatesDict, Field(alias="coordinates", repr=False)
]
"""Coordinates dictionary that identify the location of the action instance on the device."""
@property
def coordinates(self) -> Coordinates:
"""Coordinates that identify the location of the action instance on the device."""
return Coordinates(**self.coordinates_obj)
class StatefulActionPayloadMixin:
"""Mixin class for payload models that have an optional state field."""
state: Optional[int] = None # noqa: UP007
"""Current state of the action.
Only applicable to actions that have multiple states defined within the manifest.json file.
"""
class SingleActionPayloadMixin:
"""Mixin class for event models that have a single action payload."""
is_in_multi_action: Annotated[Literal[False], Field(alias="isInMultiAction")]
"""Indicates that this event is not part of a multi-action."""
class MultiActionPayloadMixin:
"""Mixin class for event models that have a multi-action payload."""
is_in_multi_action: Annotated[Literal[True], Field(alias="isInMultiAction")]
"""Indicates that this event is part of a multi-action."""
# These need to be covariant, as the Mixin classes are never meant to be instantiated themselves, only inherited from.
SingleActionPayload_co = TypeVar("SingleActionPayload_co", bound=SingleActionPayloadMixin, covariant=True)
MultiActionPayload_co = TypeVar("MultiActionPayload_co", bound=MultiActionPayloadMixin, covariant=True)
CardinalityDiscriminated = Annotated[
Union[ # noqa: UP007
SingleActionPayload_co,
MultiActionPayload_co,
],
Field(discriminator="is_in_multi_action"),
]
"""Generic type for a payload that either subclasses SingleActionPayloadMixin or MultiActionPayloadMixin—meaning it can be either a single action or a multi-action."""