Skip to content

Commit 1d98b3b

Browse files
committed
Consolidate string aliases to streamdeck.types
1 parent 9bd84a0 commit 1d98b3b

File tree

11 files changed

+114
-63
lines changed

11 files changed

+114
-63
lines changed

streamdeck/actions.py

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,12 @@
1111
from collections.abc import Callable, Generator
1212
from typing import Protocol
1313

14-
from typing_extensions import ParamSpec, TypeAlias, TypeVar # noqa: UP035
14+
from typing_extensions import ParamSpec, TypeVar
1515

1616
from streamdeck.models.events import EventBase
17+
from streamdeck.types import ActionUUIDStr, EventNameStr
1718

1819

19-
EventNameStr: TypeAlias = str # noqa: UP040
20-
"""Type alias for the event name string.
21-
22-
We don't define literal string values here, as the list of available event names can be added to dynamically.
23-
"""
24-
2520

2621
EventModel_contra = TypeVar("EventModel_contra", bound=EventBase, default=EventBase, contravariant=True)
2722
InjectableParams = ParamSpec("InjectableParams", default=...)
@@ -39,11 +34,7 @@ class ActionBase(ABC):
3934
"""Base class for all actions."""
4035

4136
def __init__(self) -> None:
42-
"""Initialize an Action instance.
43-
44-
Args:
45-
uuid (str): The unique identifier for the action.
46-
"""
37+
"""Initialize an Action instance."""
4738
self._events: dict[EventNameStr, set[EventHandlerFunc]] = defaultdict(set)
4839

4940
def on(self, event_name: EventNameStr, /) -> Callable[[EventHandlerFunc[EventModel_contra, InjectableParams]], EventHandlerFunc[EventModel_contra, InjectableParams]]:
@@ -98,7 +89,7 @@ class GlobalAction(ActionBase):
9889
class Action(ActionBase):
9990
"""Represents an action that can be performed for a specific action, with event handlers for specific event types."""
10091

101-
def __init__(self, uuid: str) -> None:
92+
def __init__(self, uuid: ActionUUIDStr) -> None:
10293
"""Initialize an Action instance.
10394
10495
Args:
@@ -128,7 +119,7 @@ def register(self, action: ActionBase) -> None:
128119
"""
129120
self._plugin_actions.append(action)
130121

131-
def get_action_handlers(self, event_name: EventNameStr, event_action_uuid: str | None = None) -> Generator[EventHandlerFunc, None, None]:
122+
def get_action_handlers(self, event_name: EventNameStr, event_action_uuid: ActionUUIDStr | None = None) -> Generator[EventHandlerFunc, None, None]:
132123
"""Get all event handlers for a specific event from all registered actions.
133124
134125
Args:

streamdeck/command_sender.py

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@
77
if TYPE_CHECKING:
88
from typing import Any, Literal
99

10+
from streamdeck.types import (
11+
ActionInstanceUUIDStr,
12+
ActionUUIDStr,
13+
DeviceUUIDStr,
14+
EventNameStr,
15+
PluginDefinedData,
16+
)
1017
from streamdeck.websocket import WebSocketClient
1118

1219

@@ -16,30 +23,31 @@
1623

1724
class StreamDeckCommandSender:
1825
"""Class for sending command event messages to the Stream Deck software through a WebSocket client."""
26+
1927
def __init__(self, client: WebSocketClient, plugin_registration_uuid: str):
2028
self._client = client
2129
self._plugin_registration_uuid = plugin_registration_uuid
2230

23-
def _send_event(self, event: str, **kwargs: Any) -> None:
31+
def _send_event(self, event: EventNameStr, **kwargs: Any) -> None:
2432
self._client.send_event({
2533
"event": event,
2634
**kwargs,
2735
})
2836

29-
def set_settings(self, context: str, payload: dict[str, Any]) -> None:
37+
def set_settings(self, context: ActionInstanceUUIDStr, payload: PluginDefinedData) -> None:
3038
self._send_event(
3139
event="setSettings",
3240
context=context,
3341
payload=payload,
3442
)
3543

36-
def get_settings(self, context: str) -> None:
44+
def get_settings(self, context: ActionInstanceUUIDStr) -> None:
3745
self._send_event(
3846
event="getSettings",
3947
context=context,
4048
)
4149

42-
def set_global_settings(self, payload: dict[str, Any]) -> None:
50+
def set_global_settings(self, payload: PluginDefinedData) -> None:
4351
self._send_event(
4452
event="setGlobalSettings",
4553
context=self._plugin_registration_uuid,
@@ -52,14 +60,14 @@ def get_global_settings(self) -> None:
5260
context=self._plugin_registration_uuid,
5361
)
5462

55-
def open_url(self, context: str, url: str) -> None:
63+
def open_url(self, context: ActionInstanceUUIDStr, url: str) -> None:
5664
self._send_event(
5765
event="openUrl",
5866
context=context,
5967
payload={"url": url},
6068
)
6169

62-
def log_message(self, context: str, message: str) -> None:
70+
def log_message(self, context: ActionInstanceUUIDStr, message: str) -> None:
6371
self._send_event(
6472
event="logMessage",
6573
context=context,
@@ -68,10 +76,10 @@ def log_message(self, context: str, message: str) -> None:
6876

6977
def set_title(
7078
self,
71-
context: str,
79+
context: ActionInstanceUUIDStr,
7280
state: int | None = None,
73-
target: str | None = None,
74-
title: str | None = None
81+
target: Literal["hardware", "software", "both"] | None = None,
82+
title: str | None = None,
7583
) -> None:
7684
payload = {}
7785

@@ -90,10 +98,10 @@ def set_title(
9098

9199
def set_image(
92100
self,
93-
context: str,
94-
image: str, # base64 encoded image,
95-
target: Literal["hardware", "software", "both"], # software, hardware, or both,
96-
state: int, # 0-based integer
101+
context: ActionInstanceUUIDStr,
102+
image: str, # base64 encoded image,
103+
target: Literal["hardware", "software", "both"],
104+
state: int,
97105
) -> None:
98106
"""...
99107
@@ -117,14 +125,26 @@ def set_image(
117125
},
118126
)
119127

120-
def set_feedback(self, context: str, payload: dict[str, Any]) -> None:
128+
def set_feedback(self, context: ActionInstanceUUIDStr, payload: PluginDefinedData) -> None:
129+
"""Set's the feedback of an existing layout associated with an action instance.
130+
131+
Args:
132+
context (str): Defines the context of the command, e.g. which action instance the command is intended for.
133+
payload (PluginDefinedData): Additional information supplied as part of the command.
134+
"""
121135
self._send_event(
122136
event="setFeedback",
123137
context=context,
124138
payload=payload,
125139
)
126140

127-
def set_feedback_layout(self, context: str, layout: str) -> None:
141+
def set_feedback_layout(self, context: ActionInstanceUUIDStr, layout: str) -> None:
142+
"""Sets the layout associated with an action instance.
143+
144+
Args:
145+
context (str): Defines the context of the command, e.g. which action instance the command is intended for.
146+
layout (str): Name of a pre-defined layout, or relative path to a custom one.
147+
"""
128148
self._send_event(
129149
event="setFeedbackLayout",
130150
context=context,
@@ -133,7 +153,7 @@ def set_feedback_layout(self, context: str, layout: str) -> None:
133153

134154
def set_trigger_description(
135155
self,
136-
context: str,
156+
context: ActionInstanceUUIDStr,
137157
rotate: str | None = None,
138158
push: str | None = None,
139159
touch: str | None = None,
@@ -170,21 +190,21 @@ def set_trigger_description(
170190
},
171191
)
172192

173-
def show_alert(self, context: str) -> None:
193+
def show_alert(self, context: ActionInstanceUUIDStr) -> None:
174194
"""Temporarily show an alert icon on the image displayed by an instance of an action."""
175195
self._send_event(
176196
event="showAlert",
177197
context=context,
178198
)
179199

180-
def show_ok(self, context: str) -> None:
200+
def show_ok(self, context: ActionInstanceUUIDStr) -> None:
181201
"""Temporarily show an OK checkmark icon on the image displayed by an instance of an action."""
182202
self._send_event(
183203
event="showOk",
184204
context=context,
185205
)
186206

187-
def set_state(self, context: str, state: int) -> None:
207+
def set_state(self, context: ActionInstanceUUIDStr, state: int) -> None:
188208
self._send_event(
189209
event="setState",
190210
context=context,
@@ -193,8 +213,8 @@ def set_state(self, context: str, state: int) -> None:
193213

194214
def switch_to_profile(
195215
self,
196-
context: str,
197-
device: str,
216+
context: ActionInstanceUUIDStr,
217+
device: DeviceUUIDStr,
198218
profile: str | None = None,
199219
page: int = 0,
200220
) -> None:
@@ -211,7 +231,7 @@ def switch_to_profile(
211231
page (int): Page to show when switching to the profile; indexed from 0.
212232
"""
213233
# TODO: Should validation happen that ensures the specified profile is declared in manifest.yaml?
214-
payload = {}
234+
payload: dict[str, str | int | None] = {}
215235

216236
if profile is not None:
217237
payload = {
@@ -226,18 +246,17 @@ def switch_to_profile(
226246
payload=payload,
227247
)
228248

229-
def send_to_property_inspector(self, context: str, payload: dict[str, Any]) -> None:
249+
def send_to_property_inspector(
250+
self, context: ActionInstanceUUIDStr, payload: PluginDefinedData
251+
) -> None:
230252
self._send_event(
231253
event="sendToPropertyInspector",
232254
context=context,
233255
payload=payload,
234256
)
235257

236258
def send_to_plugin(
237-
self,
238-
context: str,
239-
action: str,
240-
payload: dict[str, Any]
259+
self, context: ActionInstanceUUIDStr, action: ActionUUIDStr, payload: PluginDefinedData
241260
) -> None:
242261
"""Send a payload to another plugin.
243262

streamdeck/models/events/__init__.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
if TYPE_CHECKING:
3232
from typing import Final
3333

34+
from streamdeck.types import EventNameStr
35+
36+
3437

3538
DEFAULT_EVENT_MODELS: Final[list[type[EventBase]]] = [
3639
ApplicationDidLaunch,
@@ -56,16 +59,16 @@
5659
]
5760

5861

59-
def _get_default_event_names() -> set[str]:
60-
default_event_names: set[str] = set()
62+
def _get_default_event_names() -> set[EventNameStr]:
63+
default_event_names: set[EventNameStr] = set()
6164

6265
for event_model in DEFAULT_EVENT_MODELS:
6366
default_event_names.update(event_model.get_model_event_names())
6467

6568
return default_event_names
6669

6770

68-
DEFAULT_EVENT_NAMES: Final[set[str]] = _get_default_event_names()
71+
DEFAULT_EVENT_NAMES: Final[set[EventNameStr]] = _get_default_event_names()
6972

7073

7174

streamdeck/models/events/adapter.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88

99

1010
if TYPE_CHECKING:
11+
from typing_extensions import TypeIs
12+
1113
from streamdeck.models.events.base import EventBase
14+
from streamdeck.types import EventNameStr
1215

1316

1417
class EventAdapter:
@@ -17,7 +20,7 @@ def __init__(self) -> None:
1720
self._models: list[type[EventBase]] = []
1821
self._type_adapter: TypeAdapter[EventBase] | None = None
1922

20-
self._event_names: set[str] = set()
23+
self._event_names: set[EventNameStr] = set()
2124
"""A set of all event names that have been registered with the adapter.
2225
This set starts out containing the default event models defined by the library.
2326
"""
@@ -32,7 +35,7 @@ def add_model(self, model: type[EventBase]) -> None:
3235
# so `get_model_event_names()` returns a tuple of all event names, even if there is only one.
3336
self._event_names.update(model.get_model_event_names())
3437

35-
def event_name_exists(self, event_name: str) -> bool:
38+
def event_name_exists(self, event_name: str) -> TypeIs[EventNameStr]:
3639
"""Check if an event name has been registered with the adapter."""
3740
return event_name in self._event_names
3841

streamdeck/models/events/base.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ class EventMetadataDict(TypedDict):
5555

5656
from pydantic._internal._model_construction import ModelMetaclass # type: ignore[import]
5757

58+
from streamdeck.types import EventNameStr
59+
5860
class EventMeta(ModelMetaclass):
5961
"""Metaclass for EventBase stub to satisfy static type checkers."""
6062
@classmethod
@@ -78,7 +80,7 @@ class TestEvent(EventBase["test", "testing"]):
7880
7981
```
8082
"""
81-
event: LiteralString
83+
event: EventNameStr
8284
"""Name of the event used to identify what occurred.
8385
8486
Subclass models must define this field as a Literal type with the event name string that the model represents.
@@ -89,7 +91,7 @@ class TestEvent(EventBase["test", "testing"]):
8991
"""Return the event type for the event model."""
9092

9193
@classmethod
92-
def get_model_event_names(cls) -> tuple[str, ...]:
94+
def get_model_event_names(cls) -> tuple[EventNameStr, ...]:
9395
"""Return the event names for the event model."""
9496
...
9597

streamdeck/models/events/common.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,38 @@
33
from abc import ABC
44
from typing import Annotated, Generic, Literal, NamedTuple, Optional, Union
55

6-
from pydantic import Field, JsonValue
6+
from pydantic import Field
77
from typing_extensions import TypedDict, TypeVar
88

99
from streamdeck.models.events.base import ConfiguredBaseModel
10+
from streamdeck.types import ( # noqa: TC001
11+
ActionInstanceUUIDStr,
12+
DeviceUUIDStr,
13+
EventNameStr,
14+
PluginDefinedData,
15+
)
1016

1117

1218
## Mixin classes for common event model fields.
1319

1420
class ContextualEventMixin:
1521
"""Mixin class for event models that have action and context fields."""
16-
action: str
22+
action: EventNameStr
1723
"""Unique identifier of the action"""
18-
context: str
24+
context: ActionInstanceUUIDStr
1925
"""Identifies the instance of an action that caused the event, i.e. the specific key or dial."""
2026

2127

2228
class DeviceSpecificEventMixin:
2329
"""Mixin class for event models that have a device field."""
24-
device: str
30+
device: DeviceUUIDStr
2531
"""Unique identifier of the Stream Deck device that this event is associated with."""
2632

2733

2834
## Payload models and metadata used by multiple event models.
2935

3036

31-
PluginDefinedData = dict[str, JsonValue]
32-
"""Data of arbitrary structure that is defined in and relevant to the plugin.
3337

34-
The root of the data structure will always be a dict of string keys, while the values can be any JSON-compatible type.
35-
"""
3638

3739

3840
EncoderControllerType = Literal["Encoder"]

streamdeck/models/events/property_inspector.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
from streamdeck.models.events.common import (
55
ContextualEventMixin,
66
DeviceSpecificEventMixin,
7-
PluginDefinedData,
87
)
8+
from streamdeck.types import PluginDefinedData # noqa: TC001
99

1010

1111
class DidReceivePropertyInspectorMessage(EventBase["sendToPlugin"], ContextualEventMixin):

0 commit comments

Comments
 (0)