streamdeck 0.9.6__tar.gz → 0.9.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. {streamdeck-0.9.6 → streamdeck-0.9.7}/CHANGELOG +6 -0
  2. {streamdeck-0.9.6 → streamdeck-0.9.7}/PKG-INFO +17 -3
  3. {streamdeck-0.9.6 → streamdeck-0.9.7}/README.md +5 -0
  4. streamdeck-0.9.7/VERSION +1 -0
  5. {streamdeck-0.9.6 → streamdeck-0.9.7}/setup.py +1 -1
  6. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/StreamDeck/DeviceManager.py +11 -14
  7. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/StreamDeck/Devices/StreamDeck.py +58 -50
  8. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/StreamDeck/ImageHelpers/PILHelper.py +19 -17
  9. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/StreamDeck/ProductIDs.py +11 -6
  10. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/StreamDeck/Transport/LibUSBHIDAPI.py +10 -13
  11. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/StreamDeck/Transport/Transport.py +13 -13
  12. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/example_animated.py +1 -1
  13. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/example_basic.py +2 -1
  14. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/example_neo.py +2 -1
  15. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/example_pedal.py +2 -1
  16. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/example_plus.py +2 -1
  17. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/example_tileimage.py +2 -1
  18. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/streamdeck.egg-info/PKG-INFO +17 -3
  19. streamdeck-0.9.6/VERSION +0 -1
  20. {streamdeck-0.9.6 → streamdeck-0.9.7}/ExampleDeck.jpg +0 -0
  21. {streamdeck-0.9.6 → streamdeck-0.9.7}/LICENSE +0 -0
  22. {streamdeck-0.9.6 → streamdeck-0.9.7}/MANIFEST.in +0 -0
  23. {streamdeck-0.9.6 → streamdeck-0.9.7}/setup.cfg +0 -0
  24. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/Assets/Apache License 2.0.txt +0 -0
  25. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/Assets/Attribution.txt +0 -0
  26. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/Assets/CC BY-SA 3.0 License.txt +0 -0
  27. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/Assets/CC0 License.txt +0 -0
  28. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/Assets/Elephant_Walking_animated.gif +0 -0
  29. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/Assets/Exit.png +0 -0
  30. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/Assets/Harold.jpg +0 -0
  31. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/Assets/Pressed.png +0 -0
  32. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/Assets/RGB_color_space_animated_view.gif +0 -0
  33. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/Assets/Released.png +0 -0
  34. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/Assets/Roboto-Regular.ttf +0 -0
  35. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/Assets/Simple_CV_Joint_animated.gif +0 -0
  36. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/StreamDeck/Devices/StreamDeckMini.py +0 -0
  37. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/StreamDeck/Devices/StreamDeckNeo.py +0 -0
  38. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/StreamDeck/Devices/StreamDeckOriginal.py +0 -0
  39. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/StreamDeck/Devices/StreamDeckOriginalV2.py +0 -0
  40. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/StreamDeck/Devices/StreamDeckPedal.py +0 -0
  41. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/StreamDeck/Devices/StreamDeckPlus.py +0 -0
  42. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/StreamDeck/Devices/StreamDeckXL.py +0 -0
  43. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/StreamDeck/Devices/__init__.py +0 -0
  44. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/StreamDeck/ImageHelpers/__init__.py +0 -0
  45. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/StreamDeck/Transport/Dummy.py +0 -0
  46. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/StreamDeck/Transport/__init__.py +0 -0
  47. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/StreamDeck/__init__.py +0 -0
  48. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/example_deckinfo.py +0 -0
  49. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/streamdeck.egg-info/SOURCES.txt +0 -0
  50. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/streamdeck.egg-info/dependency_links.txt +0 -0
  51. {streamdeck-0.9.6 → streamdeck-0.9.7}/src/streamdeck.egg-info/top_level.txt +0 -0
  52. {streamdeck-0.9.6 → streamdeck-0.9.7}/test/test.py +0 -0
@@ -1,3 +1,9 @@
1
+ Version 0.9.7:
2
+ - Added type hints to public APIs.
3
+ - Fixed leading whitespace in StreamDeck Plus serial number strings.
4
+ - Added support for new PID variant of the StreamDeck MK2.
5
+ - Added support for new StreamDeck 16-key, 32-key and scissor modules.
6
+
1
7
  Version 0.9.6:
2
8
  - Fixed StreamDeck+ returning 10 key states instead of the expected 8.
3
9
  - Fixed StreamDeck+ dial push event not being detected correctly.
@@ -1,14 +1,23 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: streamdeck
3
- Version: 0.9.6
3
+ Version: 0.9.7
4
4
  Summary: Library to control Elgato StreamDeck devices.
5
5
  Home-page: https://github.com/abcminiuser/python-elgato-streamdeck
6
6
  Author: Dean Camera
7
7
  Author-email: dean@fourwalledcubicle.com
8
8
  License: MIT
9
- Requires-Python: >=3.8
9
+ Requires-Python: >=3.9
10
10
  Description-Content-Type: text/markdown
11
11
  License-File: LICENSE
12
+ Dynamic: author
13
+ Dynamic: author-email
14
+ Dynamic: description
15
+ Dynamic: description-content-type
16
+ Dynamic: home-page
17
+ Dynamic: license
18
+ Dynamic: license-file
19
+ Dynamic: requires-python
20
+ Dynamic: summary
12
21
 
13
22
  # Python Elgato Stream Deck Library
14
23
 
@@ -32,6 +41,7 @@ the images shown on each button, and read the current button states.
32
41
  Currently the following StreamDeck products are supported in multiple hardware
33
42
  variants:
34
43
 
44
+ * StreamDeck 16 Key, 32 Key and Scissor Modules
35
45
  * StreamDeck Mini
36
46
  * StreamDeck Neo
37
47
  * StreamDeck Original
@@ -79,16 +89,20 @@ development and maintenance of this library:
79
89
  - [dubstech](https://github.com/dubstech)
80
90
  - [Giraut](https://github.com/Giraut)
81
91
  - [impala454](https://github.com/impala454)
92
+ - [iPhoneAddict](https://github.com/iPhoneAddict)
82
93
  - [itsusony](https://github.com/itsusony)
83
94
  - [jakobbuis](https://github.com/jakobbuis)
84
95
  - [jmudge14](https://github.com/jmudge14)
96
+ - [jonbloom](https://github.com/jonbloom)
85
97
  - [Kalle-Wirsch](https://github.com/Kalle-Wirsch)
86
98
  - [karstlok](https://github.com/karstlok)
87
99
  - [Lewiscowles1986](https://github.com/Lewiscowles1986)
88
100
  - [m-weigand](https://github.com/m-weigand)
101
+ - [mathben](https://github.com/mathben)
89
102
  - [matrixinius](https://github.com/matrixinius)
90
103
  - [phillco](https://github.com/phillco)
91
104
  - [pointshader](https://github.com/pointshader)
105
+ - [pylogger-html](https://github.com/pylogger-html)
92
106
  - [shanna](https://github.com/shanna)
93
107
  - [spidererrol](https://github.com/Spidererrol)
94
108
  - [spyoungtech](https://github.com/spyoungtech)
@@ -20,6 +20,7 @@ the images shown on each button, and read the current button states.
20
20
  Currently the following StreamDeck products are supported in multiple hardware
21
21
  variants:
22
22
 
23
+ * StreamDeck 16 Key, 32 Key and Scissor Modules
23
24
  * StreamDeck Mini
24
25
  * StreamDeck Neo
25
26
  * StreamDeck Original
@@ -67,16 +68,20 @@ development and maintenance of this library:
67
68
  - [dubstech](https://github.com/dubstech)
68
69
  - [Giraut](https://github.com/Giraut)
69
70
  - [impala454](https://github.com/impala454)
71
+ - [iPhoneAddict](https://github.com/iPhoneAddict)
70
72
  - [itsusony](https://github.com/itsusony)
71
73
  - [jakobbuis](https://github.com/jakobbuis)
72
74
  - [jmudge14](https://github.com/jmudge14)
75
+ - [jonbloom](https://github.com/jonbloom)
73
76
  - [Kalle-Wirsch](https://github.com/Kalle-Wirsch)
74
77
  - [karstlok](https://github.com/karstlok)
75
78
  - [Lewiscowles1986](https://github.com/Lewiscowles1986)
76
79
  - [m-weigand](https://github.com/m-weigand)
80
+ - [mathben](https://github.com/mathben)
77
81
  - [matrixinius](https://github.com/matrixinius)
78
82
  - [phillco](https://github.com/phillco)
79
83
  - [pointshader](https://github.com/pointshader)
84
+ - [pylogger-html](https://github.com/pylogger-html)
80
85
  - [shanna](https://github.com/shanna)
81
86
  - [spidererrol](https://github.com/Spidererrol)
82
87
  - [spyoungtech](https://github.com/spyoungtech)
@@ -0,0 +1 @@
1
+ 0.9.7
@@ -20,5 +20,5 @@ setuptools.setup(
20
20
  long_description=long_description,
21
21
  long_description_content_type="text/markdown",
22
22
  include_package_data=True,
23
- python_requires='>=3.8',
23
+ python_requires='>=3.9',
24
24
  )
@@ -5,6 +5,7 @@
5
5
  # www.fourwalledcubicle.com
6
6
  #
7
7
 
8
+ from .Devices.StreamDeck import StreamDeck
8
9
  from .Devices.StreamDeckMini import StreamDeckMini
9
10
  from .Devices.StreamDeckNeo import StreamDeckNeo
10
11
  from .Devices.StreamDeckOriginal import StreamDeckOriginal
@@ -12,6 +13,7 @@ from .Devices.StreamDeckOriginalV2 import StreamDeckOriginalV2
12
13
  from .Devices.StreamDeckXL import StreamDeckXL
13
14
  from .Devices.StreamDeckPedal import StreamDeckPedal
14
15
  from .Devices.StreamDeckPlus import StreamDeckPlus
16
+ from .Transport import Transport
15
17
  from .Transport.Dummy import Dummy
16
18
  from .Transport.LibUSBHIDAPI import LibUSBHIDAPI
17
19
  from .ProductIDs import USBVendorIDs, USBProductIDs
@@ -33,18 +35,8 @@ class DeviceManager:
33
35
  StreamDeck devices.
34
36
  """
35
37
 
36
- USB_VID_ELGATO = 0x0fd9
37
- USB_PID_STREAMDECK_ORIGINAL = 0x0060
38
- USB_PID_STREAMDECK_ORIGINAL_V2 = 0x006d
39
- USB_PID_STREAMDECK_MINI = 0x0063
40
- USB_PID_STREAMDECK_NEO = 0x009a
41
- USB_PID_STREAMDECK_XL = 0x006c
42
- USB_PID_STREAMDECK_MK2 = 0x0080
43
- USB_PID_STREAMDECK_PEDAL = 0x0086
44
- USB_PID_STREAMDECK_PLUS = 0x0084
45
-
46
38
  @staticmethod
47
- def _get_transport(transport):
39
+ def _get_transport(transport: str | None):
48
40
  """
49
41
  Creates a new HID transport instance from the given transport back-end
50
42
  name. If no specific transport is supplied, an attempt to find an
@@ -87,15 +79,15 @@ class DeviceManager:
87
79
 
88
80
  raise ProbeError("Probe failed to find any functional HID backend.", probe_errors)
89
81
 
90
- def __init__(self, transport=None):
82
+ def __init__(self, transport: str | None = None):
91
83
  """
92
84
  Creates a new StreamDeck DeviceManager, used to detect attached StreamDeck devices.
93
85
 
94
86
  :param str transport: name of the the specific HID transport back-end to use, None to auto-probe.
95
87
  """
96
- self.transport = self._get_transport(transport)
88
+ self.transport: Transport.Transport = self._get_transport(transport)
97
89
 
98
- def enumerate(self):
90
+ def enumerate(self) -> list[StreamDeck]:
99
91
  """
100
92
  Detect attached StreamDeck devices.
101
93
 
@@ -106,13 +98,18 @@ class DeviceManager:
106
98
  products = [
107
99
  (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_ORIGINAL, StreamDeckOriginal),
108
100
  (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_ORIGINAL_V2, StreamDeckOriginalV2),
101
+ (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_MK2_SCISSOR, StreamDeckOriginalV2),
102
+ (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_MK2_MODULE, StreamDeckOriginalV2),
109
103
  (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_MINI, StreamDeckMini),
110
104
  (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_NEO, StreamDeckNeo),
111
105
  (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_XL, StreamDeckXL),
112
106
  (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_MK2, StreamDeckOriginalV2),
107
+ (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_MK2_V2, StreamDeckOriginalV2),
113
108
  (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_PEDAL, StreamDeckPedal),
114
109
  (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_MINI_MK2, StreamDeckMini),
110
+ (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_MINI_MK2_MODULE, StreamDeckMini),
115
111
  (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_XL_V2, StreamDeckXL),
112
+ (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_XL_V2_MODULE, StreamDeckXL),
116
113
  (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_PLUS, StreamDeckPlus),
117
114
  ]
118
115
 
@@ -8,9 +8,11 @@
8
8
  import threading
9
9
  import time
10
10
  from abc import ABC, abstractmethod
11
+ from collections.abc import Callable
11
12
  from enum import Enum
13
+ from typing import Any, Iterable, TypeVar
12
14
 
13
- from ..Transport.Transport import TransportError
15
+ from ..Transport.Transport import Transport, TransportError
14
16
 
15
17
 
16
18
  class TouchscreenEventType(Enum):
@@ -78,19 +80,24 @@ class StreamDeck(ABC):
78
80
  DECK_VISUAL = False
79
81
  DECK_TOUCH = False
80
82
 
81
- def __init__(self, device):
82
- self.device = device
83
- self.last_key_states = [False] * (self.KEY_COUNT + self.TOUCH_KEY_COUNT)
84
- self.last_dial_states = [False] * self.DIAL_COUNT
85
- self.read_thread = None
86
- self.run_read_thread = False
87
- self.read_poll_hz = 20
83
+ _Self = TypeVar('_Self', bound='StreamDeck')
84
+ KeyCallback = Callable[[_Self, int, bool], None] | None
85
+ DialCallback = Callable[[_Self, int, DialEventType, bool], None] | None
86
+ TouchScreenCallback = Callable[[_Self, TouchscreenEventType, Any], None] | None
88
87
 
89
- self.key_callback = None
90
- self.dial_callback = None
91
- self.touchscreen_callback = None
88
+ def __init__(self, device: Transport.Device):
89
+ self.device: Transport.Device = device
90
+ self.last_key_states: list[bool] = [False] * (self.KEY_COUNT + self.TOUCH_KEY_COUNT)
91
+ self.last_dial_states: list[bool] = [False] * self.DIAL_COUNT
92
+ self.read_thread: threading.Thread | None = None
93
+ self.run_read_thread: bool = False
94
+ self.read_poll_hz: int = 20
92
95
 
93
- self.update_lock = threading.RLock()
96
+ self.key_callback: StreamDeck.KeyCallback = None
97
+ self.dial_callback: StreamDeck.DialCallback = None
98
+ self.touchscreen_callback: StreamDeck.TouchScreenCallback = None
99
+
100
+ self.update_lock: threading.RLock = threading.RLock()
94
101
 
95
102
  def __del__(self):
96
103
  """
@@ -124,7 +131,7 @@ class StreamDeck(ABC):
124
131
  self.update_lock.release()
125
132
 
126
133
  @abstractmethod
127
- def _read_control_states(self):
134
+ def _read_control_states(self) -> None:
128
135
  """
129
136
  Reads the raw key states from an attached StreamDeck.
130
137
 
@@ -133,7 +140,7 @@ class StreamDeck(ABC):
133
140
  pass
134
141
 
135
142
  @abstractmethod
136
- def _reset_key_stream(self):
143
+ def _reset_key_stream(self) -> None:
137
144
  """
138
145
  Sends a blank key report to the StreamDeck, resetting the key image
139
146
  streamer in the device. This prevents previously started partial key
@@ -142,15 +149,16 @@ class StreamDeck(ABC):
142
149
  """
143
150
  pass
144
151
 
145
- def _extract_string(self, data):
152
+ def _extract_string(self, data: Iterable[int]) -> str:
146
153
  """
147
154
  Extracts out a human-readable string from a collection of raw bytes,
148
- removing any trailing whitespace or data after the first NUL byte.
155
+ removing any trailing whitespace or data after and before the first NUL
156
+ byte.
149
157
  """
150
158
 
151
- return str(bytes(data), 'ascii', 'replace').partition('\0')[0].rstrip()
159
+ return str(bytes(data), 'ascii', 'replace').partition('\0')[0].strip()
152
160
 
153
- def _read(self):
161
+ def _read(self) -> None:
154
162
  """
155
163
  Read handler for the underlying transport, listening for control state
156
164
  changes on the underlying device, caching the new states and firing off
@@ -200,7 +208,7 @@ class StreamDeck(ABC):
200
208
  self.run_read_thread = False
201
209
  self.close()
202
210
 
203
- def _setup_reader(self, callback):
211
+ def _setup_reader(self, callback: Callable) -> None:
204
212
  """
205
213
  Sets up the internal transport reader thread with the given callback,
206
214
  for asynchronous processing of HID events from the device. If the thread
@@ -223,7 +231,7 @@ class StreamDeck(ABC):
223
231
  self.read_thread.daemon = True
224
232
  self.read_thread.start()
225
233
 
226
- def open(self):
234
+ def open(self) -> None:
227
235
  """
228
236
  Opens the device for input/output. This must be called prior to setting
229
237
  or retrieving any device state.
@@ -235,7 +243,7 @@ class StreamDeck(ABC):
235
243
  self._reset_key_stream()
236
244
  self._setup_reader(self._read)
237
245
 
238
- def close(self):
246
+ def close(self) -> None:
239
247
  """
240
248
  Closes the device for input/output.
241
249
 
@@ -243,7 +251,7 @@ class StreamDeck(ABC):
243
251
  """
244
252
  self.device.close()
245
253
 
246
- def is_open(self):
254
+ def is_open(self) -> bool:
247
255
  """
248
256
  Indicates if the StreamDeck device is currently open and ready for use.
249
257
 
@@ -252,7 +260,7 @@ class StreamDeck(ABC):
252
260
  """
253
261
  return self.device.is_open()
254
262
 
255
- def connected(self):
263
+ def connected(self) -> bool:
256
264
  """
257
265
  Indicates if the physical StreamDeck device this instance is attached to
258
266
  is still connected to the host.
@@ -262,7 +270,7 @@ class StreamDeck(ABC):
262
270
  """
263
271
  return self.device.connected()
264
272
 
265
- def vendor_id(self):
273
+ def vendor_id(self) -> int:
266
274
  """
267
275
  Retrieves the vendor ID attached StreamDeck. This can be used
268
276
  to determine the exact type of attached StreamDeck.
@@ -272,7 +280,7 @@ class StreamDeck(ABC):
272
280
  """
273
281
  return self.device.vendor_id()
274
282
 
275
- def product_id(self):
283
+ def product_id(self) -> int:
276
284
  """
277
285
  Retrieves the product ID attached StreamDeck. This can be used
278
286
  to determine the exact type of attached StreamDeck.
@@ -282,7 +290,7 @@ class StreamDeck(ABC):
282
290
  """
283
291
  return self.device.product_id()
284
292
 
285
- def id(self):
293
+ def id(self) -> str:
286
294
  """
287
295
  Retrieves the physical ID of the attached StreamDeck. This can be used
288
296
  to differentiate one StreamDeck from another.
@@ -292,7 +300,7 @@ class StreamDeck(ABC):
292
300
  """
293
301
  return self.device.path()
294
302
 
295
- def key_count(self):
303
+ def key_count(self) -> int:
296
304
  """
297
305
  Retrieves number of physical buttons on the attached StreamDeck device.
298
306
 
@@ -301,7 +309,7 @@ class StreamDeck(ABC):
301
309
  """
302
310
  return self.KEY_COUNT
303
311
 
304
- def touch_key_count(self):
312
+ def touch_key_count(self) -> int:
305
313
  """
306
314
  Retrieves number of touch buttons on the attached StreamDeck device.
307
315
 
@@ -310,7 +318,7 @@ class StreamDeck(ABC):
310
318
  """
311
319
  return self.TOUCH_KEY_COUNT
312
320
 
313
- def dial_count(self):
321
+ def dial_count(self) -> int:
314
322
  """
315
323
  Retrieves number of physical dials on the attached StreamDeck device.
316
324
 
@@ -319,7 +327,7 @@ class StreamDeck(ABC):
319
327
  """
320
328
  return self.DIAL_COUNT
321
329
 
322
- def deck_type(self):
330
+ def deck_type(self) -> str:
323
331
  """
324
332
  Retrieves the model of Stream Deck.
325
333
 
@@ -328,7 +336,7 @@ class StreamDeck(ABC):
328
336
  """
329
337
  return self.DECK_TYPE
330
338
 
331
- def is_visual(self):
339
+ def is_visual(self) -> bool:
332
340
  """
333
341
  Returns whether the Stream Deck has a visual display output.
334
342
 
@@ -337,7 +345,7 @@ class StreamDeck(ABC):
337
345
  """
338
346
  return self.DECK_VISUAL
339
347
 
340
- def is_touch(self):
348
+ def is_touch(self) -> bool:
341
349
  """
342
350
  Returns whether the Stream Deck can receive touch events
343
351
 
@@ -346,7 +354,7 @@ class StreamDeck(ABC):
346
354
  """
347
355
  return self.DECK_TOUCH
348
356
 
349
- def key_layout(self):
357
+ def key_layout(self) -> tuple[int, int]:
350
358
  """
351
359
  Retrieves the physical button layout on the attached StreamDeck device.
352
360
 
@@ -414,7 +422,7 @@ class StreamDeck(ABC):
414
422
  'rotation': self.SCREEN_ROTATION,
415
423
  }
416
424
 
417
- def set_poll_frequency(self, hz):
425
+ def set_poll_frequency(self, hz: int) -> None:
418
426
  """
419
427
  Sets the frequency of the button polling reader thread, determining how
420
428
  often the StreamDeck will be polled for button changes.
@@ -426,7 +434,7 @@ class StreamDeck(ABC):
426
434
  """
427
435
  self.read_poll_hz = min(max(hz, 1), 1000)
428
436
 
429
- def set_key_callback(self, callback):
437
+ def set_key_callback(self, callback: KeyCallback) -> None:
430
438
  """
431
439
  Sets the callback function called each time a button on the StreamDeck
432
440
  changes state (either pressed, or released).
@@ -445,7 +453,7 @@ class StreamDeck(ABC):
445
453
  """
446
454
  self.key_callback = callback
447
455
 
448
- def set_key_callback_async(self, async_callback, loop=None):
456
+ def set_key_callback_async(self, async_callback: KeyCallback, loop=None):
449
457
  """
450
458
  Sets the asynchronous callback function called each time a button on the
451
459
  StreamDeck changes state (either pressed, or released). The given
@@ -470,7 +478,7 @@ class StreamDeck(ABC):
470
478
 
471
479
  self.set_key_callback(callback)
472
480
 
473
- def set_dial_callback(self, callback):
481
+ def set_dial_callback(self, callback: DialCallback) -> None:
474
482
  """
475
483
  Sets the callback function called each time there is an interaction
476
484
  with a dial on the StreamDeck.
@@ -489,7 +497,7 @@ class StreamDeck(ABC):
489
497
  """
490
498
  self.dial_callback = callback
491
499
 
492
- def set_dial_callback_async(self, async_callback, loop=None):
500
+ def set_dial_callback_async(self, async_callback: DialCallback, loop=None) -> None:
493
501
  """
494
502
  Sets the asynchronous callback function called each time there is an
495
503
  interaction with a dial on the StreamDeck. The given callback should
@@ -514,7 +522,7 @@ class StreamDeck(ABC):
514
522
 
515
523
  self.set_dial_callback(callback)
516
524
 
517
- def set_touchscreen_callback(self, callback):
525
+ def set_touchscreen_callback(self, callback: TouchScreenCallback) -> None:
518
526
  """
519
527
  Sets the callback function called each time there is an interaction
520
528
  with a touchscreen on the StreamDeck.
@@ -533,7 +541,7 @@ class StreamDeck(ABC):
533
541
  """
534
542
  self.touchscreen_callback = callback
535
543
 
536
- def set_touchscreen_callback_async(self, async_callback, loop=None):
544
+ def set_touchscreen_callback_async(self, async_callback: TouchScreenCallback, loop=None) -> None:
537
545
  """
538
546
  Sets the asynchronous callback function called each time there is an
539
547
  interaction with the touchscreen on the StreamDeck. The given callback
@@ -558,7 +566,7 @@ class StreamDeck(ABC):
558
566
 
559
567
  self.set_touchscreen_callback(callback)
560
568
 
561
- def key_states(self):
569
+ def key_states(self) -> list[bool]:
562
570
  """
563
571
  Retrieves the current states of the buttons on the StreamDeck.
564
572
 
@@ -569,7 +577,7 @@ class StreamDeck(ABC):
569
577
  """
570
578
  return self.last_key_states
571
579
 
572
- def dial_states(self):
580
+ def dial_states(self) -> list[bool]:
573
581
  """
574
582
  Retrieves the current states of the dials (pressed or not) on the
575
583
  Stream Deck
@@ -582,7 +590,7 @@ class StreamDeck(ABC):
582
590
  return self.last_dial_states
583
591
 
584
592
  @abstractmethod
585
- def reset(self):
593
+ def reset(self) -> None:
586
594
  """
587
595
  Resets the StreamDeck, clearing all button images and showing the
588
596
  standby image.
@@ -590,7 +598,7 @@ class StreamDeck(ABC):
590
598
  pass
591
599
 
592
600
  @abstractmethod
593
- def set_brightness(self, percent):
601
+ def set_brightness(self, percent: int | float) -> None:
594
602
  """
595
603
  Sets the global screen brightness of the StreamDeck, across all the
596
604
  physical buttons.
@@ -601,7 +609,7 @@ class StreamDeck(ABC):
601
609
  pass
602
610
 
603
611
  @abstractmethod
604
- def get_serial_number(self):
612
+ def get_serial_number(self) -> str:
605
613
  """
606
614
  Gets the serial number of the attached StreamDeck.
607
615
 
@@ -611,7 +619,7 @@ class StreamDeck(ABC):
611
619
  pass
612
620
 
613
621
  @abstractmethod
614
- def get_firmware_version(self):
622
+ def get_firmware_version(self) -> str:
615
623
  """
616
624
  Gets the firmware version of the attached StreamDeck.
617
625
 
@@ -621,7 +629,7 @@ class StreamDeck(ABC):
621
629
  pass
622
630
 
623
631
  @abstractmethod
624
- def set_key_image(self, key, image):
632
+ def set_key_image(self, key: int, image: bytes) -> None:
625
633
  """
626
634
  Sets the image of a button on the StreamDeck to the given image. The
627
635
  image being set should be in the correct format for the device, as an
@@ -638,7 +646,7 @@ class StreamDeck(ABC):
638
646
  pass
639
647
 
640
648
  @abstractmethod
641
- def set_touchscreen_image(self, image, x_pos=0, y_pos=0, width=0, height=0):
649
+ def set_touchscreen_image(self, image: bytes, x_pos: int = 0, y_pos: int = 0, width: int = 0, height: int = 0):
642
650
  """
643
651
  Draws an image on the touchscreen in a certain position. The image
644
652
  should be in the correct format for the devices, as an enumerable
@@ -658,7 +666,7 @@ class StreamDeck(ABC):
658
666
  pass
659
667
 
660
668
  @abstractmethod
661
- def set_key_color(self, key, r, g, b):
669
+ def set_key_color(self, key: int, r: int, g: int, b: int) -> None:
662
670
  """
663
671
  Sets the color of the touch buttons. These buttons are indexed
664
672
  in order after the standard keys.
@@ -672,7 +680,7 @@ class StreamDeck(ABC):
672
680
  pass
673
681
 
674
682
  @abstractmethod
675
- def set_screen_image(self, image):
683
+ def set_screen_image(self, image: bytes) -> None:
676
684
  """
677
685
  Draws an image on the touchless screen of the StreamDeck.
678
686
 
@@ -8,12 +8,14 @@
8
8
  import io
9
9
  from PIL import Image
10
10
 
11
+ from ..Devices.StreamDeck import StreamDeck
12
+
11
13
 
12
14
  def _create_image(image_format, background):
13
15
  return Image.new("RGB", image_format['size'], background)
14
16
 
15
17
 
16
- def _scale_image(image, image_format, margins=[0, 0, 0, 0], background='black'):
18
+ def _scale_image(image, image_format, margins=(0, 0, 0, 0), background='black'):
17
19
  if len(margins) != 4:
18
20
  raise ValueError("Margins should be given as an array of four integers.")
19
21
 
@@ -47,12 +49,12 @@ def _to_native_format(image, image_format):
47
49
  image = image.transpose(Image.FLIP_TOP_BOTTOM)
48
50
 
49
51
  # We want a compressed image in a given codec, convert.
50
- compressed_image = io.BytesIO()
51
- image.save(compressed_image, image_format['format'], quality=100)
52
- return compressed_image.getbuffer()
52
+ with io.BytesIO() as compressed_image:
53
+ image.save(compressed_image, image_format['format'], quality=100)
54
+ return compressed_image.getvalue()
53
55
 
54
56
 
55
- def create_image(deck, background='black'):
57
+ def create_image(deck: StreamDeck, background: str = 'black') -> Image.Image:
56
58
  """
57
59
  .. deprecated:: 0.9.5
58
60
  Use :func:`~PILHelper.create_key_image` method instead.
@@ -60,7 +62,7 @@ def create_image(deck, background='black'):
60
62
  return create_key_image(deck, background)
61
63
 
62
64
 
63
- def create_key_image(deck, background='black'):
65
+ def create_key_image(deck: StreamDeck, background: str = 'black') -> Image.Image:
64
66
  """
65
67
  Creates a new PIL Image with the correct image dimensions for the given
66
68
  StreamDeck device's keys.
@@ -78,7 +80,7 @@ def create_key_image(deck, background='black'):
78
80
  return _create_image(deck.key_image_format(), background)
79
81
 
80
82
 
81
- def create_touchscreen_image(deck, background='black'):
83
+ def create_touchscreen_image(deck: StreamDeck, background: str = 'black') -> Image.Image:
82
84
  """
83
85
  Creates a new PIL Image with the correct image dimensions for the given
84
86
  StreamDeck device's touchscreen.
@@ -96,10 +98,10 @@ def create_touchscreen_image(deck, background='black'):
96
98
  return _create_image(deck.touchscreen_image_format(), background)
97
99
 
98
100
 
99
- def create_screen_image(deck, background='black'):
101
+ def create_screen_image(deck: StreamDeck, background: str = 'black') -> Image.Image:
100
102
  """
101
103
  Creates a new PIL Image with the correct image dimensions for the given
102
- StreamDeck device's creen.
104
+ StreamDeck device's screen.
103
105
 
104
106
  .. seealso:: See :func:`~PILHelper.to_native_screen_format` method for converting a
105
107
  PIL image instance to the native screen image format of a given
@@ -114,7 +116,7 @@ def create_screen_image(deck, background='black'):
114
116
  return _create_image(deck.screen_image_format(), background)
115
117
 
116
118
 
117
- def create_scaled_image(deck, image, margins=[0, 0, 0, 0], background='black'):
119
+ def create_scaled_image(deck: StreamDeck, image: Image.Image, margins: tuple[int, int, int, int] = (0, 0, 0, 0), background: str = 'black') -> Image.Image:
118
120
  """
119
121
  .. deprecated:: 0.9.5
120
122
  Use :func:`~PILHelper.create_scaled_key_image` method instead.
@@ -122,7 +124,7 @@ def create_scaled_image(deck, image, margins=[0, 0, 0, 0], background='black'):
122
124
  return create_scaled_key_image(deck, image, margins, background)
123
125
 
124
126
 
125
- def create_scaled_key_image(deck, image, margins=[0, 0, 0, 0], background='black'):
127
+ def create_scaled_key_image(deck: StreamDeck, image: Image.Image, margins: tuple[int, int, int, int] = (0, 0, 0, 0), background: str = 'black') -> Image.Image:
126
128
  """
127
129
  Creates a new key image that contains a scaled version of a given image,
128
130
  resized to best fit the given StreamDeck device's keys with the given
@@ -146,7 +148,7 @@ def create_scaled_key_image(deck, image, margins=[0, 0, 0, 0], background='black
146
148
  return _scale_image(image, deck.key_image_format(), margins, background)
147
149
 
148
150
 
149
- def create_scaled_touchscreen_image(deck, image, margins=[0, 0, 0, 0], background='black'):
151
+ def create_scaled_touchscreen_image(deck: StreamDeck, image: Image.Image, margins: tuple[int, int, int, int] = (0, 0, 0, 0), background: str = 'black') -> Image.Image:
150
152
  """
151
153
  Creates a new touchscreen image that contains a scaled version of a given image,
152
154
  resized to best fit the given StreamDeck device's touchscreen with the given
@@ -170,7 +172,7 @@ def create_scaled_touchscreen_image(deck, image, margins=[0, 0, 0, 0], backgroun
170
172
  return _scale_image(image, deck.touchscreen_image_format(), margins, background)
171
173
 
172
174
 
173
- def create_scaled_screen_image(deck, image, margins=[0, 0, 0, 0], background='black'):
175
+ def create_scaled_screen_image(deck: StreamDeck, image: Image.Image, margins: tuple[int, int, int, int] = (0, 0, 0, 0), background: str = 'black') -> Image.Image:
174
176
  """
175
177
  Creates a new screen image that contains a scaled version of a given image,
176
178
  resized to best fit the given StreamDeck device's screen with the given
@@ -194,7 +196,7 @@ def create_scaled_screen_image(deck, image, margins=[0, 0, 0, 0], background='bl
194
196
  return _scale_image(image, deck.screen_image_format(), margins, background)
195
197
 
196
198
 
197
- def to_native_format(deck, image):
199
+ def to_native_format(deck: StreamDeck, image: Image.Image) -> bytes:
198
200
  """
199
201
  .. deprecated:: 0.9.5
200
202
  Use :func:`~PILHelper.to_native_key_format` method instead.
@@ -202,7 +204,7 @@ def to_native_format(deck, image):
202
204
  return to_native_key_format(deck, image)
203
205
 
204
206
 
205
- def to_native_key_format(deck, image):
207
+ def to_native_key_format(deck: StreamDeck, image: Image.Image) -> bytes:
206
208
  """
207
209
  Converts a given PIL image to the native key image format for a StreamDeck,
208
210
  suitable for passing to :func:`~StreamDeck.set_key_image`.
@@ -219,7 +221,7 @@ def to_native_key_format(deck, image):
219
221
  return _to_native_format(image, deck.key_image_format())
220
222
 
221
223
 
222
- def to_native_touchscreen_format(deck, image):
224
+ def to_native_touchscreen_format(deck: StreamDeck, image: Image.Image) -> bytes:
223
225
  """
224
226
  Converts a given PIL image to the native touchscreen image format for a StreamDeck,
225
227
  suitable for passing to :func:`~StreamDeck.set_touchscreen_image`.
@@ -236,7 +238,7 @@ def to_native_touchscreen_format(deck, image):
236
238
  return _to_native_format(image, deck.touchscreen_image_format())
237
239
 
238
240
 
239
- def to_native_screen_format(deck, image):
241
+ def to_native_screen_format(deck: StreamDeck, image: Image.Image) -> bytes:
240
242
  """
241
243
  Converts a given PIL image to the native screen image format for a StreamDeck,
242
244
  suitable for passing to :func:`~StreamDeck.set_screen_image`.
@@ -19,13 +19,18 @@ class USBProductIDs:
19
19
  USB Product IDs for known StreamDeck devices.
20
20
  """
21
21
 
22
- USB_PID_STREAMDECK_ORIGINAL = 0x0060
23
- USB_PID_STREAMDECK_ORIGINAL_V2 = 0x006d
24
22
  USB_PID_STREAMDECK_MINI = 0x0063
25
- USB_PID_STREAMDECK_NEO = 0x009a
26
- USB_PID_STREAMDECK_XL = 0x006c
27
- USB_PID_STREAMDECK_XL_V2 = 0x008f
23
+ USB_PID_STREAMDECK_MINI_MK2 = 0x0090
24
+ USB_PID_STREAMDECK_MINI_MK2_MODULE = 0x00b8
28
25
  USB_PID_STREAMDECK_MK2 = 0x0080
26
+ USB_PID_STREAMDECK_MK2_MODULE = 0x00b9
27
+ USB_PID_STREAMDECK_MK2_SCISSOR = 0x00a5
28
+ USB_PID_STREAMDECK_MK2_V2 = 0x00B9
29
+ USB_PID_STREAMDECK_NEO = 0x009a
30
+ USB_PID_STREAMDECK_ORIGINAL = 0x0060
31
+ USB_PID_STREAMDECK_ORIGINAL_V2 = 0x006d
29
32
  USB_PID_STREAMDECK_PEDAL = 0x0086
30
- USB_PID_STREAMDECK_MINI_MK2 = 0x0090
31
33
  USB_PID_STREAMDECK_PLUS = 0x0084
34
+ USB_PID_STREAMDECK_XL = 0x006c
35
+ USB_PID_STREAMDECK_XL_V2 = 0x008f
36
+ USB_PID_STREAMDECK_XL_V2_MODULE = 0x00ba
@@ -213,7 +213,6 @@ class LibUSBHIDAPI(Transport):
213
213
  :rtype: Handle
214
214
  :return: Device handle if opened successfully, None if open failed.
215
215
  """
216
-
217
216
  with self.mutex:
218
217
  if type(path) is not bytes:
219
218
  path = bytes(path, 'utf-8')
@@ -250,10 +249,10 @@ class LibUSBHIDAPI(Transport):
250
249
  :rtype: int
251
250
  :return: Number of bytes successfully sent to the device.
252
251
  """
253
- with self.mutex:
254
- if not handle:
255
- raise TransportError("No HID device.")
252
+ if not handle:
253
+ raise TransportError("No HID device.")
256
254
 
255
+ with self.mutex:
257
256
  result = self.hidapi.hid_send_feature_report(handle, bytes(data), len(data))
258
257
 
259
258
  if result < 0:
@@ -274,6 +273,8 @@ class LibUSBHIDAPI(Transport):
274
273
  first byte of the report will be the Report ID of the
275
274
  report that was read.
276
275
  """
276
+ if not handle:
277
+ raise TransportError("No HID device.")
277
278
 
278
279
  # We may need to oversize our read due a bug in some versions of
279
280
  # HIDAPI. Only applied on Mac systems, as this will cause other
@@ -284,9 +285,6 @@ class LibUSBHIDAPI(Transport):
284
285
  data[0] = report_id
285
286
 
286
287
  with self.mutex:
287
- if not handle:
288
- raise TransportError("No HID device.")
289
-
290
288
  result = self.hidapi.hid_get_feature_report(handle, data, len(data))
291
289
 
292
290
  if result < 0:
@@ -313,10 +311,10 @@ class LibUSBHIDAPI(Transport):
313
311
  :rtype: int
314
312
  :return: Number of bytes successfully sent to the device.
315
313
  """
316
- with self.mutex:
317
- if not handle:
318
- raise TransportError("No HID device.")
314
+ if not handle:
315
+ raise TransportError("No HID device.")
319
316
 
317
+ with self.mutex:
320
318
  result = self.hidapi.hid_write(handle, bytes(data), len(data))
321
319
 
322
320
  if result < 0:
@@ -336,13 +334,12 @@ class LibUSBHIDAPI(Transport):
336
334
  first byte of the report will be the Report ID of the
337
335
  report that was read.
338
336
  """
337
+ if not handle:
338
+ raise TransportError("No HID device.")
339
339
 
340
340
  data = ctypes.create_string_buffer(length)
341
341
 
342
342
  with self.mutex:
343
- if not handle:
344
- raise TransportError("No HID device.")
345
-
346
343
  result = self.hidapi.hid_read(handle, data, len(data))
347
344
 
348
345
  if result < 0:
@@ -31,7 +31,7 @@ class Transport(ABC):
31
31
  """
32
32
 
33
33
  @abstractmethod
34
- def open(self):
34
+ def open(self) -> None:
35
35
  """
36
36
  Opens the device for input/output. This must be called prior to
37
37
  sending or receiving any reports.
@@ -42,7 +42,7 @@ class Transport(ABC):
42
42
  pass
43
43
 
44
44
  @abstractmethod
45
- def close(self):
45
+ def close(self) -> None:
46
46
  """
47
47
  Closes the device for input/output.
48
48
 
@@ -52,7 +52,7 @@ class Transport(ABC):
52
52
  pass
53
53
 
54
54
  @abstractmethod
55
- def is_open(self):
55
+ def is_open(self) -> bool:
56
56
  """
57
57
  Indicates if the physical device object this instance is attached
58
58
  to has been opened by the host.
@@ -63,7 +63,7 @@ class Transport(ABC):
63
63
  pass
64
64
 
65
65
  @abstractmethod
66
- def connected(self):
66
+ def connected(self) -> bool:
67
67
  """
68
68
  Indicates if the physical device object this instance is attached
69
69
  to is still connected to the host.
@@ -74,7 +74,7 @@ class Transport(ABC):
74
74
  pass
75
75
 
76
76
  @abstractmethod
77
- def path(self):
77
+ def path(self) -> str:
78
78
  """
79
79
  Retrieves the logical path of the attached device within the
80
80
  current system. This can be used to uniquely differentiate one
@@ -86,7 +86,7 @@ class Transport(ABC):
86
86
  pass
87
87
 
88
88
  @abstractmethod
89
- def vendor_id(self):
89
+ def vendor_id(self) -> int:
90
90
  """
91
91
  Retrieves the vendor ID value of the attached device.
92
92
 
@@ -96,7 +96,7 @@ class Transport(ABC):
96
96
  pass
97
97
 
98
98
  @abstractmethod
99
- def product_id(self):
99
+ def product_id(self) -> int:
100
100
  """
101
101
  Retrieves the product ID value of the attached device.
102
102
 
@@ -106,7 +106,7 @@ class Transport(ABC):
106
106
  pass
107
107
 
108
108
  @abstractmethod
109
- def write_feature(self, payload):
109
+ def write_feature(self, payload: bytes) -> int:
110
110
  """
111
111
  Sends a HID Feature report to the open HID device.
112
112
 
@@ -121,7 +121,7 @@ class Transport(ABC):
121
121
  pass
122
122
 
123
123
  @abstractmethod
124
- def read_feature(self, report_id, length):
124
+ def read_feature(self, report_id: int, length: int) -> bytes:
125
125
  """
126
126
  Reads a HID Feature report from the open HID device.
127
127
 
@@ -136,7 +136,7 @@ class Transport(ABC):
136
136
  pass
137
137
 
138
138
  @abstractmethod
139
- def write(self, payload):
139
+ def write(self, payload: bytes) -> int:
140
140
  """
141
141
  Sends a HID Out report to the open HID device.
142
142
 
@@ -151,7 +151,7 @@ class Transport(ABC):
151
151
  pass
152
152
 
153
153
  @abstractmethod
154
- def read(self, length):
154
+ def read(self, length: int) -> bytes:
155
155
  """
156
156
  Performs a blocking read of a HID In report from the open HID device.
157
157
 
@@ -166,7 +166,7 @@ class Transport(ABC):
166
166
 
167
167
  @staticmethod
168
168
  @abstractmethod
169
- def probe():
169
+ def probe() -> None:
170
170
  """
171
171
  Attempts to determine if the back-end is installed and usable. It is
172
172
  expected that probe failures throw exceptions detailing their exact
@@ -175,7 +175,7 @@ class Transport(ABC):
175
175
  pass
176
176
 
177
177
  @abstractmethod
178
- def enumerate(self, vid, pid):
178
+ def enumerate(self, vid: int, pid: int) -> list[Device]:
179
179
  """
180
180
  Enumerates all available devices on the system using the current
181
181
  transport back-end.
@@ -168,5 +168,5 @@ if __name__ == "__main__":
168
168
  for t in threading.enumerate():
169
169
  try:
170
170
  t.join()
171
- except RuntimeError:
171
+ except (TransportError, RuntimeError):
172
172
  pass
@@ -16,6 +16,7 @@ import threading
16
16
  from PIL import Image, ImageDraw, ImageFont
17
17
  from StreamDeck.DeviceManager import DeviceManager
18
18
  from StreamDeck.ImageHelpers import PILHelper
19
+ from StreamDeck.Transport.Transport import TransportError
19
20
 
20
21
  # Folder location of image assets used by this example.
21
22
  ASSETS_PATH = os.path.join(os.path.dirname(__file__), "Assets")
@@ -140,5 +141,5 @@ if __name__ == "__main__":
140
141
  for t in threading.enumerate():
141
142
  try:
142
143
  t.join()
143
- except RuntimeError:
144
+ except (TransportError, RuntimeError):
144
145
  pass
@@ -17,6 +17,7 @@ import random
17
17
  from PIL import Image, ImageDraw, ImageFont
18
18
  from StreamDeck.DeviceManager import DeviceManager
19
19
  from StreamDeck.ImageHelpers import PILHelper
20
+ from StreamDeck.Transport.Transport import TransportError
20
21
 
21
22
  # Folder location of image assets used by this example.
22
23
  ASSETS_PATH = os.path.join(os.path.dirname(__file__), "Assets")
@@ -166,5 +167,5 @@ if __name__ == "__main__":
166
167
  for t in threading.enumerate():
167
168
  try:
168
169
  t.join()
169
- except RuntimeError:
170
+ except (TransportError, RuntimeError):
170
171
  pass
@@ -14,6 +14,7 @@
14
14
  import threading
15
15
 
16
16
  from StreamDeck.DeviceManager import DeviceManager
17
+ from StreamDeck.Transport.Transport import TransportError
17
18
 
18
19
 
19
20
  def key_change_callback(deck, key, state):
@@ -40,5 +41,5 @@ if __name__ == "__main__":
40
41
  for t in threading.enumerate():
41
42
  try:
42
43
  t.join()
43
- except RuntimeError:
44
+ except (TransportError, RuntimeError):
44
45
  pass
@@ -14,6 +14,7 @@ import io
14
14
  from PIL import Image
15
15
  from StreamDeck.DeviceManager import DeviceManager
16
16
  from StreamDeck.Devices.StreamDeck import DialEventType, TouchscreenEventType
17
+ from StreamDeck.Transport.Transport import TransportError
17
18
 
18
19
  # Folder location of image assets used by this example.
19
20
  ASSETS_PATH = os.path.join(os.path.dirname(__file__), "Assets")
@@ -131,5 +132,5 @@ if __name__ == "__main__":
131
132
  for t in threading.enumerate():
132
133
  try:
133
134
  t.join()
134
- except RuntimeError:
135
+ except (TransportError, RuntimeError):
135
136
  pass
@@ -17,6 +17,7 @@ import threading
17
17
  from PIL import Image, ImageOps
18
18
  from StreamDeck.DeviceManager import DeviceManager
19
19
  from StreamDeck.ImageHelpers import PILHelper
20
+ from StreamDeck.Transport.Transport import TransportError
20
21
 
21
22
  # Folder location of image assets used by this example.
22
23
  ASSETS_PATH = os.path.join(os.path.dirname(__file__), "Assets")
@@ -144,5 +145,5 @@ if __name__ == "__main__":
144
145
  for t in threading.enumerate():
145
146
  try:
146
147
  t.join()
147
- except RuntimeError:
148
+ except (TransportError, RuntimeError):
148
149
  pass
@@ -1,14 +1,23 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: streamdeck
3
- Version: 0.9.6
3
+ Version: 0.9.7
4
4
  Summary: Library to control Elgato StreamDeck devices.
5
5
  Home-page: https://github.com/abcminiuser/python-elgato-streamdeck
6
6
  Author: Dean Camera
7
7
  Author-email: dean@fourwalledcubicle.com
8
8
  License: MIT
9
- Requires-Python: >=3.8
9
+ Requires-Python: >=3.9
10
10
  Description-Content-Type: text/markdown
11
11
  License-File: LICENSE
12
+ Dynamic: author
13
+ Dynamic: author-email
14
+ Dynamic: description
15
+ Dynamic: description-content-type
16
+ Dynamic: home-page
17
+ Dynamic: license
18
+ Dynamic: license-file
19
+ Dynamic: requires-python
20
+ Dynamic: summary
12
21
 
13
22
  # Python Elgato Stream Deck Library
14
23
 
@@ -32,6 +41,7 @@ the images shown on each button, and read the current button states.
32
41
  Currently the following StreamDeck products are supported in multiple hardware
33
42
  variants:
34
43
 
44
+ * StreamDeck 16 Key, 32 Key and Scissor Modules
35
45
  * StreamDeck Mini
36
46
  * StreamDeck Neo
37
47
  * StreamDeck Original
@@ -79,16 +89,20 @@ development and maintenance of this library:
79
89
  - [dubstech](https://github.com/dubstech)
80
90
  - [Giraut](https://github.com/Giraut)
81
91
  - [impala454](https://github.com/impala454)
92
+ - [iPhoneAddict](https://github.com/iPhoneAddict)
82
93
  - [itsusony](https://github.com/itsusony)
83
94
  - [jakobbuis](https://github.com/jakobbuis)
84
95
  - [jmudge14](https://github.com/jmudge14)
96
+ - [jonbloom](https://github.com/jonbloom)
85
97
  - [Kalle-Wirsch](https://github.com/Kalle-Wirsch)
86
98
  - [karstlok](https://github.com/karstlok)
87
99
  - [Lewiscowles1986](https://github.com/Lewiscowles1986)
88
100
  - [m-weigand](https://github.com/m-weigand)
101
+ - [mathben](https://github.com/mathben)
89
102
  - [matrixinius](https://github.com/matrixinius)
90
103
  - [phillco](https://github.com/phillco)
91
104
  - [pointshader](https://github.com/pointshader)
105
+ - [pylogger-html](https://github.com/pylogger-html)
92
106
  - [shanna](https://github.com/shanna)
93
107
  - [spidererrol](https://github.com/Spidererrol)
94
108
  - [spyoungtech](https://github.com/spyoungtech)
streamdeck-0.9.6/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.9.6
File without changes
File without changes
File without changes
File without changes
File without changes