lifx-async 5.0.0__py3-none-any.whl → 5.0.1__py3-none-any.whl

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.
lifx/const.py CHANGED
@@ -1,5 +1,7 @@
1
1
  # lifx-async constants
2
2
 
3
+ import asyncio
4
+ import sys
3
5
  import uuid
4
6
  from typing import Final
5
7
 
@@ -109,3 +111,19 @@ PROTOCOL_URL: Final[str] = (
109
111
  PRODUCTS_URL: Final[str] = (
110
112
  "https://raw.githubusercontent.com/LIFX/products/refs/heads/master/products.json"
111
113
  )
114
+
115
+ # ============================================================================
116
+ # Python Version Compatibility
117
+ # ============================================================================
118
+
119
+ # On Python 3.10, asyncio.wait_for() raises asyncio.TimeoutError which is NOT
120
+ # a subclass of the built-in TimeoutError. In Python 3.11+, they are unified.
121
+ # Use this tuple with `except TIMEOUT_ERRORS:` to catch timeouts from asyncio
122
+ # operations on all supported Python versions.
123
+ if sys.version_info < (3, 11):
124
+ TIMEOUT_ERRORS: Final[tuple[type[BaseException], ...]] = (
125
+ TimeoutError,
126
+ asyncio.TimeoutError,
127
+ )
128
+ else:
129
+ TIMEOUT_ERRORS: Final[tuple[type[BaseException], ...]] = (TimeoutError,)
lifx/effects/colorloop.py CHANGED
@@ -11,7 +11,7 @@ import random
11
11
  from typing import TYPE_CHECKING
12
12
 
13
13
  from lifx.color import HSBK
14
- from lifx.const import KELVIN_NEUTRAL
14
+ from lifx.const import KELVIN_NEUTRAL, TIMEOUT_ERRORS
15
15
  from lifx.effects.base import LIFXEffect
16
16
 
17
17
  if TYPE_CHECKING:
@@ -172,7 +172,7 @@ class EffectColorloop(LIFXEffect):
172
172
  self._stop_event.wait(), timeout=iteration_period
173
173
  )
174
174
  break # Stop event was set
175
- except TimeoutError:
175
+ except TIMEOUT_ERRORS:
176
176
  pass # Normal - continue to next iteration
177
177
 
178
178
  iteration += 1
@@ -17,6 +17,7 @@ from lifx.const import (
17
17
  DEFAULT_MAX_RETRIES,
18
18
  DEFAULT_REQUEST_TIMEOUT,
19
19
  LIFX_UDP_PORT,
20
+ TIMEOUT_ERRORS,
20
21
  )
21
22
  from lifx.exceptions import (
22
23
  LifxConnectionError,
@@ -193,7 +194,7 @@ class DeviceConnection:
193
194
  await asyncio.wait_for(
194
195
  self._receiver_task, timeout=_RECEIVER_SHUTDOWN_TIMEOUT
195
196
  )
196
- except TimeoutError:
197
+ except TIMEOUT_ERRORS:
197
198
  self._receiver_task.cancel()
198
199
  try:
199
200
  await self._receiver_task
@@ -559,7 +560,7 @@ class DeviceConnection:
559
560
  header, payload = await asyncio.wait_for(
560
561
  response_queue.get(), timeout=remaining_time
561
562
  )
562
- except TimeoutError:
563
+ except TIMEOUT_ERRORS:
563
564
  if not has_yielded:
564
565
  # No response this attempt, retry
565
566
  raise TimeoutError(
@@ -603,7 +604,7 @@ class DeviceConnection:
603
604
 
604
605
  # Continue loop to wait for more responses
605
606
 
606
- except TimeoutError as e:
607
+ except TIMEOUT_ERRORS as e:
607
608
  last_error = LifxTimeoutError(str(e))
608
609
  if attempt < max_retries:
609
610
  # Sleep with jitter before retry
@@ -702,7 +703,7 @@ class DeviceConnection:
702
703
  header, _payload = await asyncio.wait_for(
703
704
  response_queue.get(), timeout=current_timeout
704
705
  )
705
- except TimeoutError:
706
+ except TIMEOUT_ERRORS:
706
707
  raise TimeoutError(
707
708
  f"No acknowledgement within {current_timeout:.3f}s "
708
709
  f"(attempt {attempt + 1}/{max_retries + 1})"
@@ -731,7 +732,7 @@ class DeviceConnection:
731
732
  yield True
732
733
  return
733
734
 
734
- except TimeoutError as e:
735
+ except TIMEOUT_ERRORS as e:
735
736
  last_error = LifxTimeoutError(str(e))
736
737
  if attempt < max_retries:
737
738
  # Sleep with jitter before retry
@@ -13,7 +13,7 @@ import struct
13
13
  from asyncio import DatagramTransport
14
14
  from typing import TYPE_CHECKING
15
15
 
16
- from lifx.const import MDNS_ADDRESS, MDNS_PORT
16
+ from lifx.const import MDNS_ADDRESS, MDNS_PORT, TIMEOUT_ERRORS
17
17
  from lifx.exceptions import LifxNetworkError, LifxTimeoutError
18
18
 
19
19
  if TYPE_CHECKING:
@@ -259,7 +259,7 @@ class MdnsTransport:
259
259
  self._protocol.queue.get(), timeout=timeout
260
260
  )
261
261
  return data, addr
262
- except TimeoutError as e:
262
+ except TIMEOUT_ERRORS as e:
263
263
  raise LifxTimeoutError(f"No mDNS data received within {timeout}s") from e
264
264
  except OSError as e:
265
265
  _LOGGER.debug(
lifx/network/transport.py CHANGED
@@ -6,7 +6,12 @@ import asyncio
6
6
  import logging
7
7
  from typing import TYPE_CHECKING
8
8
 
9
- from lifx.const import DEFAULT_IP_ADDRESS, MAX_PACKET_SIZE, MIN_PACKET_SIZE
9
+ from lifx.const import (
10
+ DEFAULT_IP_ADDRESS,
11
+ MAX_PACKET_SIZE,
12
+ MIN_PACKET_SIZE,
13
+ TIMEOUT_ERRORS,
14
+ )
10
15
  from lifx.exceptions import LifxNetworkError
11
16
  from lifx.exceptions import LifxTimeoutError as LifxTimeoutError
12
17
 
@@ -208,7 +213,7 @@ class UdpTransport:
208
213
  data, addr = await asyncio.wait_for(
209
214
  self._protocol.queue.get(), timeout=timeout
210
215
  )
211
- except TimeoutError as e:
216
+ except TIMEOUT_ERRORS as e:
212
217
  raise LifxTimeoutError(f"No data received within {timeout}s") from e
213
218
  except OSError as e:
214
219
  _LOGGER.error(
@@ -302,7 +307,7 @@ class UdpTransport:
302
307
  continue
303
308
 
304
309
  packets.append((data, addr))
305
- except TimeoutError:
310
+ except TIMEOUT_ERRORS:
306
311
  # Timeout is expected - return what we collected
307
312
  break
308
313
  except OSError:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lifx-async
3
- Version: 5.0.0
3
+ Version: 5.0.1
4
4
  Summary: A modern, type-safe, async Python library for controlling LIFX lights
5
5
  Author-email: Avi Miller <me@dje.li>
6
6
  Maintainer-email: Avi Miller <me@dje.li>
@@ -1,7 +1,7 @@
1
1
  lifx/__init__.py,sha256=DKHG1vFJvPw_LpMkQgZN85gyOSD8dnceq6LnEGgR9vs,2810
2
2
  lifx/api.py,sha256=tTE9H8eSVrFIr6rEGxedWoR4ChnqvTz2EUgEQk60fgU,35428
3
3
  lifx/color.py,sha256=UfeoOiFgFih5edl2Ei-0wSzvZXRTI47yUm9GlNJZeTw,26041
4
- lifx/const.py,sha256=5LEh4h0-bEJlOfpG8fgyht0LkAEV9jkkpuCiuatBhEI,3840
4
+ lifx/const.py,sha256=M_6d1yFaWzalUAWzrVHv6BOIOu_1f6JJslP267Vd_kg,4573
5
5
  lifx/exceptions.py,sha256=pikAMppLn7gXyjiQVWM_tSvXKNh-g366nG_UWyqpHhc,815
6
6
  lifx/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  lifx/devices/__init__.py,sha256=4b5QtO0EFWxIqN2lUYgM8uLjWyHI5hUcReiF9QCjCGw,1061
@@ -14,21 +14,21 @@ lifx/devices/matrix.py,sha256=TcfVvqFCIhGXjOtaQEARQCXe9XqSFDZ4wEQdRZBiQpA,42301
14
14
  lifx/devices/multizone.py,sha256=7Te5Z_X9hDvdypjMqPGGM2TG0P9QltzFVi7UUxRdbGI,33326
15
15
  lifx/effects/__init__.py,sha256=4DF31yp7RJic5JoltMlz5dCtF5KQobU6NOUtLUKkVKE,1509
16
16
  lifx/effects/base.py,sha256=tKgX5PsV6hipffD2B236rOzudkMwWq59-eQGnfvNKdU,10354
17
- lifx/effects/colorloop.py,sha256=Yz9XcQ_VhTPSnJn1s4WnkoXTRh2_qFJrPhQkIiTF6Tk,15574
17
+ lifx/effects/colorloop.py,sha256=LYlljT7XfaQ-S3mWNMWZ-3q7ce1cfl8nmyLb-VuXTZE,15592
18
18
  lifx/effects/conductor.py,sha256=Oaq-6m1kdUF6bma_U9GcA9onZzh6YRjpExBr-OGHQJI,14552
19
19
  lifx/effects/const.py,sha256=03LfL8v9PtoUs6-2IR3aa6nkyA4Otdno51SFJtntC-U,795
20
20
  lifx/effects/models.py,sha256=MS5D-cxD0Ar8XhqbqKAc9q2sk38IP1vPkYwd8V7jCr8,2446
21
21
  lifx/effects/pulse.py,sha256=k4dtBhhgVHyuwzqzx89jYVKbSRUVQdZj91cklyKarbE,8455
22
22
  lifx/effects/state_manager.py,sha256=iDfYowiCN5IJqcR1s-pM0mQEJpe-RDsMcOOSMmtPVDE,8983
23
23
  lifx/network/__init__.py,sha256=uSyA8r8qISG7qXUHbX8uk9A2E8rvDADgCcf94QIZ9so,499
24
- lifx/network/connection.py,sha256=qPKEkhr9DvoL2cCJoIlDi8rowNS-gUn_F3mesnzyFjs,38412
24
+ lifx/network/connection.py,sha256=_asGr6KGJIC82C0HOUa4CbfbiV8rfbppcpazUrmcA0c,38442
25
25
  lifx/network/discovery.py,sha256=syFfkDYWo0AEoBdEBjWqBm4K7UJwZW5x2K0FBMiA2I0,24186
26
26
  lifx/network/message.py,sha256=jCLC9v0tbBi54g5CaHLFM_nP1Izu8kJmo2tt23HHBbA,2600
27
- lifx/network/transport.py,sha256=io_3SFYQliNa_upHcKRzrLUkDVsDmNsxa2gQMlxj7Zk,10912
27
+ lifx/network/transport.py,sha256=EykhKmvjAcdiepgCxgzDTj8Fc0b7kAQdyR8AumGXohg,10953
28
28
  lifx/network/mdns/__init__.py,sha256=LlZgsFe6q5_SIXvXqtuZ_O9tJbcJZ-nsFkD2_wD8_TM,1412
29
29
  lifx/network/mdns/discovery.py,sha256=EZ2zlJmy96rMDmu5J-68ystXJ2gYa18zTYP3iqmTGgU,13200
30
30
  lifx/network/mdns/dns.py,sha256=OsvNSxLepIG3Nhw-kkQF3JrBYI-ikod5SHD2HO5_yGE,9363
31
- lifx/network/mdns/transport.py,sha256=41E_yX9Jx42ffElTcF-73A4ma48b3xkkHnG3DTcO8u8,10250
31
+ lifx/network/mdns/transport.py,sha256=x1IzvOYSsMcTY1zGIg0Cv694KU6Pyp8CaY0YQUI_-Nc,10268
32
32
  lifx/network/mdns/types.py,sha256=9fhH5iuMQxLkFPhmFTf2-kOcUNoWEu7LrN15Qr9tFE0,990
33
33
  lifx/products/__init__.py,sha256=pf2O-fzt6nOrQd-wmzhiog91tMiGa-dDbaSNtU2ZQfE,764
34
34
  lifx/products/generator.py,sha256=DsTCJcEVPmn9sfXSbXYdFZjqMfIbodnIQL46DRASs0g,15731
@@ -47,7 +47,7 @@ lifx/theme/canvas.py,sha256=4h7lgN8iu_OdchObGDgbxTqQLCb-FRKC-M-YCWef_i4,8048
47
47
  lifx/theme/generators.py,sha256=nq3Yvntq_h-eFHbmmow3LcAdA_hEbRRaP5mv9Bydrjk,6435
48
48
  lifx/theme/library.py,sha256=tKlKZNqJp8lRGDnilWyDm_Qr1vCRGGwuvWVS82anNpQ,21326
49
49
  lifx/theme/theme.py,sha256=qMEx_8E41C0Cc6f083XHiAXEglTv4YlXW0UFsG1rQKg,5521
50
- lifx_async-5.0.0.dist-info/METADATA,sha256=Ozi93MbWMkhFydTJ_nuyQUxRLLH_iGYOxtlr0iBXe2U,2660
51
- lifx_async-5.0.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
52
- lifx_async-5.0.0.dist-info/licenses/LICENSE,sha256=eBz48GRA3gSiWn3rYZAz2Ewp35snnhV9cSqkVBq7g3k,1832
53
- lifx_async-5.0.0.dist-info/RECORD,,
50
+ lifx_async-5.0.1.dist-info/METADATA,sha256=VEs7kGoakQCCe_mxSz3Ilfx8gHXFDIAuPMUjZSinH2M,2660
51
+ lifx_async-5.0.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
52
+ lifx_async-5.0.1.dist-info/licenses/LICENSE,sha256=eBz48GRA3gSiWn3rYZAz2Ewp35snnhV9cSqkVBq7g3k,1832
53
+ lifx_async-5.0.1.dist-info/RECORD,,