lifx-async 4.3.1__tar.gz → 4.3.2__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 (144) hide show
  1. {lifx_async-4.3.1 → lifx_async-4.3.2}/.github/workflows/pr-automation.yml +2 -0
  2. {lifx_async-4.3.1 → lifx_async-4.3.2}/PKG-INFO +1 -1
  3. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/changelog.md +8 -0
  4. {lifx_async-4.3.1 → lifx_async-4.3.2}/pyproject.toml +1 -1
  5. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/effects/base.py +10 -0
  6. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/effects/colorloop.py +9 -0
  7. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/effects/pulse.py +9 -0
  8. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_effects/test_base.py +5 -0
  9. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_effects/test_colorloop.py +1 -0
  10. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_effects/test_integration.py +5 -0
  11. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_effects/test_models.py +5 -0
  12. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_effects/test_pulse.py +1 -0
  13. {lifx_async-4.3.1 → lifx_async-4.3.2}/uv.lock +1 -1
  14. {lifx_async-4.3.1 → lifx_async-4.3.2}/.claude/settings.json +0 -0
  15. {lifx_async-4.3.1 → lifx_async-4.3.2}/.github/dependabot.yml +0 -0
  16. {lifx_async-4.3.1 → lifx_async-4.3.2}/.github/labeler.yml +0 -0
  17. {lifx_async-4.3.1 → lifx_async-4.3.2}/.github/workflows/ci.yml +0 -0
  18. {lifx_async-4.3.1 → lifx_async-4.3.2}/.github/workflows/docs.yml +0 -0
  19. {lifx_async-4.3.1 → lifx_async-4.3.2}/.gitignore +0 -0
  20. {lifx_async-4.3.1 → lifx_async-4.3.2}/.pre-commit-config.yaml +0 -0
  21. {lifx_async-4.3.1 → lifx_async-4.3.2}/CLAUDE.md +0 -0
  22. {lifx_async-4.3.1 → lifx_async-4.3.2}/LICENSE +0 -0
  23. {lifx_async-4.3.1 → lifx_async-4.3.2}/README.md +0 -0
  24. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/api/colors.md +0 -0
  25. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/api/devices.md +0 -0
  26. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/api/effects.md +0 -0
  27. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/api/exceptions.md +0 -0
  28. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/api/high-level.md +0 -0
  29. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/api/index.md +0 -0
  30. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/api/network.md +0 -0
  31. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/api/protocol.md +0 -0
  32. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/api/themes.md +0 -0
  33. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/architecture/effects-architecture.md +0 -0
  34. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/architecture/overview.md +0 -0
  35. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/faq.md +0 -0
  36. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/getting-started/effects.md +0 -0
  37. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/getting-started/installation.md +0 -0
  38. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/getting-started/quickstart.md +0 -0
  39. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/getting-started/themes.md +0 -0
  40. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/index.md +0 -0
  41. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/migration/effect-api-changes.md +0 -0
  42. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/stylesheets/extra.css +0 -0
  43. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/user-guide/advanced-usage.md +0 -0
  44. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/user-guide/effects-custom.md +0 -0
  45. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/user-guide/effects-troubleshooting.md +0 -0
  46. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/user-guide/protocol-deep-dive.md +0 -0
  47. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/user-guide/themes.md +0 -0
  48. {lifx_async-4.3.1 → lifx_async-4.3.2}/docs/user-guide/troubleshooting.md +0 -0
  49. {lifx_async-4.3.1 → lifx_async-4.3.2}/examples/01_simple_discovery.py +0 -0
  50. {lifx_async-4.3.1 → lifx_async-4.3.2}/examples/02_simple_control.py +0 -0
  51. {lifx_async-4.3.1 → lifx_async-4.3.2}/examples/03_waveforms.py +0 -0
  52. {lifx_async-4.3.1 → lifx_async-4.3.2}/examples/04_logging.py +0 -0
  53. {lifx_async-4.3.1 → lifx_async-4.3.2}/examples/06_pulse_effect.py +0 -0
  54. {lifx_async-4.3.1 → lifx_async-4.3.2}/examples/07_colorloop_effect.py +0 -0
  55. {lifx_async-4.3.1 → lifx_async-4.3.2}/examples/08_custom_effect.py +0 -0
  56. {lifx_async-4.3.1 → lifx_async-4.3.2}/examples/09_background_effect.py +0 -0
  57. {lifx_async-4.3.1 → lifx_async-4.3.2}/examples/10_find_specific_devices.py +0 -0
  58. {lifx_async-4.3.1 → lifx_async-4.3.2}/examples/11_matrix_basic.py +0 -0
  59. {lifx_async-4.3.1 → lifx_async-4.3.2}/examples/12_matrix_effects.py +0 -0
  60. {lifx_async-4.3.1 → lifx_async-4.3.2}/examples/13_matrix_large.py +0 -0
  61. {lifx_async-4.3.1 → lifx_async-4.3.2}/mkdocs.yml +0 -0
  62. {lifx_async-4.3.1 → lifx_async-4.3.2}/renovate.json +0 -0
  63. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/__init__.py +0 -0
  64. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/api.py +0 -0
  65. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/color.py +0 -0
  66. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/const.py +0 -0
  67. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/devices/__init__.py +0 -0
  68. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/devices/base.py +0 -0
  69. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/devices/hev.py +0 -0
  70. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/devices/infrared.py +0 -0
  71. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/devices/light.py +0 -0
  72. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/devices/matrix.py +0 -0
  73. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/devices/multizone.py +0 -0
  74. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/effects/__init__.py +0 -0
  75. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/effects/conductor.py +0 -0
  76. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/effects/const.py +0 -0
  77. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/effects/models.py +0 -0
  78. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/effects/state_manager.py +0 -0
  79. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/exceptions.py +0 -0
  80. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/network/__init__.py +0 -0
  81. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/network/connection.py +0 -0
  82. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/network/discovery.py +0 -0
  83. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/network/message.py +0 -0
  84. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/network/transport.py +0 -0
  85. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/products/__init__.py +0 -0
  86. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/products/generator.py +0 -0
  87. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/products/registry.py +0 -0
  88. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/protocol/__init__.py +0 -0
  89. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/protocol/base.py +0 -0
  90. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/protocol/generator.py +0 -0
  91. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/protocol/header.py +0 -0
  92. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/protocol/models.py +0 -0
  93. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/protocol/packets.py +0 -0
  94. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/protocol/protocol_types.py +0 -0
  95. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/protocol/serializer.py +0 -0
  96. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/py.typed +0 -0
  97. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/theme/__init__.py +0 -0
  98. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/theme/canvas.py +0 -0
  99. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/theme/generators.py +0 -0
  100. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/theme/library.py +0 -0
  101. {lifx_async-4.3.1 → lifx_async-4.3.2}/src/lifx/theme/theme.py +0 -0
  102. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/__init__.py +0 -0
  103. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/conftest.py +0 -0
  104. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_api/__init__.py +0 -0
  105. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_api/test_api_apply_theme.py +0 -0
  106. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_api/test_api_batch_errors.py +0 -0
  107. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_api/test_api_batch_operations.py +0 -0
  108. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_api/test_api_discovery.py +0 -0
  109. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_api/test_api_organization.py +0 -0
  110. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_color.py +0 -0
  111. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_devices/__init__.py +0 -0
  112. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_devices/conftest.py +0 -0
  113. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_devices/test_base.py +0 -0
  114. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_devices/test_hev.py +0 -0
  115. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_devices/test_infrared.py +0 -0
  116. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_devices/test_light.py +0 -0
  117. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_devices/test_mac_address.py +0 -0
  118. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_devices/test_matrix.py +0 -0
  119. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_devices/test_multizone.py +0 -0
  120. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_effects/__init__.py +0 -0
  121. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_effects/test_capability_filtering.py +0 -0
  122. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_effects/test_state_manager.py +0 -0
  123. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_network/__init__.py +0 -0
  124. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_network/test_concurrent_requests.py +0 -0
  125. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_network/test_connection.py +0 -0
  126. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_network/test_discovery_devices.py +0 -0
  127. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_network/test_discovery_errors.py +0 -0
  128. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_network/test_message.py +0 -0
  129. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_network/test_message_advanced.py +0 -0
  130. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_network/test_transport.py +0 -0
  131. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_products/test_product_generator.py +0 -0
  132. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_products/test_registry.py +0 -0
  133. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_protocol/test_generated.py +0 -0
  134. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_protocol/test_header.py +0 -0
  135. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_protocol/test_protocol_generator.py +0 -0
  136. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_protocol/test_serializer.py +0 -0
  137. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_theme/__init__.py +0 -0
  138. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_theme/conftest.py +0 -0
  139. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_theme/test_apply_theme.py +0 -0
  140. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_theme/test_canvas.py +0 -0
  141. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_theme/test_generators.py +0 -0
  142. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_theme/test_library.py +0 -0
  143. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_theme/test_theme.py +0 -0
  144. {lifx_async-4.3.1 → lifx_async-4.3.2}/tests/test_utils.py +0 -0
@@ -71,6 +71,8 @@ jobs:
71
71
  docs
72
72
  ci
73
73
  deps
74
+ effects
75
+ themes
74
76
  requireScope: false
75
77
  subjectPattern: ^(?![A-Z]).+$
76
78
  subjectPatternError: |
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lifx-async
3
- Version: 4.3.1
3
+ Version: 4.3.2
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>
@@ -2,6 +2,14 @@
2
2
 
3
3
  <!-- version list -->
4
4
 
5
+ ## v4.3.2 (2025-11-22)
6
+
7
+ ### Bug Fixes
8
+
9
+ - **effects**: Add name property to LIFXEffect and subclasses
10
+ ([`deb8a54`](https://github.com/Djelibeybi/lifx-async/commit/deb8a54f674d2d4cd9b8dce519dc6ca8678e048a))
11
+
12
+
5
13
  ## v4.3.1 (2025-11-22)
6
14
 
7
15
  ### Bug Fixes
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lifx-async"
3
- version = "4.3.1"
3
+ version = "4.3.2"
4
4
  description = "A modern, type-safe, async Python library for controlling LIFX lights"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -59,6 +59,16 @@ class LIFXEffect(ABC):
59
59
  self.conductor: Conductor | None = None
60
60
  self.participants: list[Light] = []
61
61
 
62
+ @property
63
+ @abstractmethod
64
+ def name(self) -> str:
65
+ """Return the name of the effect.
66
+
67
+ Returns:
68
+ The effect name as a string
69
+ """
70
+ raise NotImplementedError("Subclasses must implement name property")
71
+
62
72
  async def async_perform(self, participants: list[Light]) -> None:
63
73
  """Perform common setup and play the effect.
64
74
 
@@ -127,6 +127,15 @@ class EffectColorloop(LIFXEffect):
127
127
  self._running = False
128
128
  self._stop_event = asyncio.Event()
129
129
 
130
+ @property
131
+ def name(self) -> str:
132
+ """Return the name of the effect.
133
+
134
+ Returns:
135
+ The effect name 'colorloop'
136
+ """
137
+ return "colorloop"
138
+
130
139
  async def async_play(self) -> None:
131
140
  """Execute the colorloop effect continuously."""
132
141
  self._running = True
@@ -136,6 +136,15 @@ class EffectPulse(LIFXEffect):
136
136
  if self.cycles < 1:
137
137
  raise ValueError(f"Cycles must be 1 or higher, got {self.cycles}")
138
138
 
139
+ @property
140
+ def name(self) -> str:
141
+ """Return the name of the effect.
142
+
143
+ Returns:
144
+ The effect name 'pulse'
145
+ """
146
+ return "pulse"
147
+
139
148
  async def async_play(self) -> None:
140
149
  """Execute the pulse effect on all participants."""
141
150
  # Determine colors for each light
@@ -13,6 +13,11 @@ from lifx.effects.const import DEFAULT_BRIGHTNESS
13
13
  class ConcreteEffect(LIFXEffect):
14
14
  """Concrete implementation for testing abstract base class."""
15
15
 
16
+ @property
17
+ def name(self) -> str:
18
+ """Return the name of the effect."""
19
+ return "test"
20
+
16
21
  async def async_play(self) -> None:
17
22
  """Minimal implementation for testing."""
18
23
  pass
@@ -14,6 +14,7 @@ def test_colorloop_default_parameters():
14
14
  """Test EffectColorloop with default parameters."""
15
15
  effect = EffectColorloop()
16
16
 
17
+ assert effect.name == "colorloop"
17
18
  assert effect.period == 60
18
19
  assert effect.change == 20
19
20
  assert effect.spread == 30
@@ -392,6 +392,11 @@ async def test_conductor_exception_during_async_perform():
392
392
 
393
393
  # Create a custom effect that raises exception during async_perform
394
394
  class FailingEffect(LIFXEffect):
395
+ @property
396
+ def name(self) -> str:
397
+ """Return the name of the effect."""
398
+ return "failing"
399
+
395
400
  async def async_play(self):
396
401
  raise RuntimeError("Effect failed during execution")
397
402
 
@@ -10,6 +10,11 @@ from lifx.effects.models import PreState, RunningEffect
10
10
  class DummyEffect(LIFXEffect):
11
11
  """Dummy effect for testing."""
12
12
 
13
+ @property
14
+ def name(self) -> str:
15
+ """Return the name of the effect."""
16
+ return "dummy"
17
+
13
18
  async def async_play(self) -> None:
14
19
  """Dummy play method."""
15
20
  pass
@@ -14,6 +14,7 @@ def test_pulse_default_mode():
14
14
  """Test EffectPulse with default mode (blink)."""
15
15
  effect = EffectPulse()
16
16
 
17
+ assert effect.name == "pulse"
17
18
  assert effect.mode == "blink"
18
19
  assert effect.period == 1.0
19
20
  assert effect.cycles == 1
@@ -432,7 +432,7 @@ wheels = [
432
432
 
433
433
  [[package]]
434
434
  name = "lifx-async"
435
- version = "4.3.1"
435
+ version = "4.3.2"
436
436
  source = { editable = "." }
437
437
 
438
438
  [package.dev-dependencies]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes