lifx-async 4.8.0__tar.gz → 4.8.1__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 (168) hide show
  1. {lifx_async-4.8.0 → lifx_async-4.8.1}/PKG-INFO +1 -1
  2. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/changelog.md +8 -0
  3. {lifx_async-4.8.0 → lifx_async-4.8.1}/pyproject.toml +1 -1
  4. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/products/generator.py +7 -5
  5. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/protocol/generator.py +7 -5
  6. {lifx_async-4.8.0 → lifx_async-4.8.1}/uv.lock +1 -1
  7. {lifx_async-4.8.0 → lifx_async-4.8.1}/.claude/settings.json +0 -0
  8. {lifx_async-4.8.0 → lifx_async-4.8.1}/.github/dependabot.yml +0 -0
  9. {lifx_async-4.8.0 → lifx_async-4.8.1}/.github/labeler.yml +0 -0
  10. {lifx_async-4.8.0 → lifx_async-4.8.1}/.github/workflows/ci.yml +0 -0
  11. {lifx_async-4.8.0 → lifx_async-4.8.1}/.github/workflows/docs.yml +0 -0
  12. {lifx_async-4.8.0 → lifx_async-4.8.1}/.github/workflows/pr-automation.yml +0 -0
  13. {lifx_async-4.8.0 → lifx_async-4.8.1}/.gitignore +0 -0
  14. {lifx_async-4.8.0 → lifx_async-4.8.1}/.pre-commit-config.yaml +0 -0
  15. {lifx_async-4.8.0 → lifx_async-4.8.1}/CLAUDE.md +0 -0
  16. {lifx_async-4.8.0 → lifx_async-4.8.1}/LICENSE +0 -0
  17. {lifx_async-4.8.0 → lifx_async-4.8.1}/README.md +0 -0
  18. {lifx_async-4.8.0 → lifx_async-4.8.1}/context7.json +0 -0
  19. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/api/colors.md +0 -0
  20. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/api/devices.md +0 -0
  21. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/api/effects.md +0 -0
  22. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/api/exceptions.md +0 -0
  23. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/api/high-level.md +0 -0
  24. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/api/index.md +0 -0
  25. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/api/network.md +0 -0
  26. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/api/protocol.md +0 -0
  27. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/api/themes.md +0 -0
  28. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/architecture/effects-architecture.md +0 -0
  29. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/architecture/overview.md +0 -0
  30. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/faq.md +0 -0
  31. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/getting-started/effects.md +0 -0
  32. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/getting-started/installation.md +0 -0
  33. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/getting-started/quickstart.md +0 -0
  34. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/getting-started/themes.md +0 -0
  35. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/index.md +0 -0
  36. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/migration/effect-api-changes.md +0 -0
  37. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/stylesheets/extra.css +0 -0
  38. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/user-guide/advanced-usage.md +0 -0
  39. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/user-guide/ceiling-lights.md +0 -0
  40. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/user-guide/effects-custom.md +0 -0
  41. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/user-guide/effects-troubleshooting.md +0 -0
  42. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/user-guide/protocol-deep-dive.md +0 -0
  43. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/user-guide/themes.md +0 -0
  44. {lifx_async-4.8.0 → lifx_async-4.8.1}/docs/user-guide/troubleshooting.md +0 -0
  45. {lifx_async-4.8.0 → lifx_async-4.8.1}/examples/01_simple_discovery.py +0 -0
  46. {lifx_async-4.8.0 → lifx_async-4.8.1}/examples/02_simple_control.py +0 -0
  47. {lifx_async-4.8.0 → lifx_async-4.8.1}/examples/03_waveforms.py +0 -0
  48. {lifx_async-4.8.0 → lifx_async-4.8.1}/examples/04_logging.py +0 -0
  49. {lifx_async-4.8.0 → lifx_async-4.8.1}/examples/06_pulse_effect.py +0 -0
  50. {lifx_async-4.8.0 → lifx_async-4.8.1}/examples/07_colorloop_effect.py +0 -0
  51. {lifx_async-4.8.0 → lifx_async-4.8.1}/examples/08_custom_effect.py +0 -0
  52. {lifx_async-4.8.0 → lifx_async-4.8.1}/examples/09_background_effect.py +0 -0
  53. {lifx_async-4.8.0 → lifx_async-4.8.1}/examples/10_find_specific_devices.py +0 -0
  54. {lifx_async-4.8.0 → lifx_async-4.8.1}/examples/11_matrix_basic.py +0 -0
  55. {lifx_async-4.8.0 → lifx_async-4.8.1}/examples/12_matrix_effects.py +0 -0
  56. {lifx_async-4.8.0 → lifx_async-4.8.1}/examples/13_matrix_large.py +0 -0
  57. {lifx_async-4.8.0 → lifx_async-4.8.1}/examples/14_mdns_discovery.py +0 -0
  58. {lifx_async-4.8.0 → lifx_async-4.8.1}/mkdocs.yml +0 -0
  59. {lifx_async-4.8.0 → lifx_async-4.8.1}/renovate.json +0 -0
  60. {lifx_async-4.8.0 → lifx_async-4.8.1}/scripts/mdns_probe.py +0 -0
  61. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/__init__.py +0 -0
  62. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/api.py +0 -0
  63. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/color.py +0 -0
  64. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/const.py +0 -0
  65. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/devices/__init__.py +0 -0
  66. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/devices/base.py +0 -0
  67. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/devices/ceiling.py +0 -0
  68. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/devices/hev.py +0 -0
  69. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/devices/infrared.py +0 -0
  70. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/devices/light.py +0 -0
  71. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/devices/matrix.py +0 -0
  72. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/devices/multizone.py +0 -0
  73. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/effects/__init__.py +0 -0
  74. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/effects/base.py +0 -0
  75. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/effects/colorloop.py +0 -0
  76. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/effects/conductor.py +0 -0
  77. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/effects/const.py +0 -0
  78. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/effects/models.py +0 -0
  79. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/effects/pulse.py +0 -0
  80. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/effects/state_manager.py +0 -0
  81. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/exceptions.py +0 -0
  82. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/network/__init__.py +0 -0
  83. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/network/connection.py +0 -0
  84. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/network/discovery.py +0 -0
  85. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/network/mdns/__init__.py +0 -0
  86. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/network/mdns/discovery.py +0 -0
  87. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/network/mdns/dns.py +0 -0
  88. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/network/mdns/transport.py +0 -0
  89. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/network/mdns/types.py +0 -0
  90. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/network/message.py +0 -0
  91. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/network/transport.py +0 -0
  92. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/products/__init__.py +0 -0
  93. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/products/quirks.py +0 -0
  94. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/products/registry.py +0 -0
  95. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/protocol/__init__.py +0 -0
  96. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/protocol/base.py +0 -0
  97. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/protocol/header.py +0 -0
  98. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/protocol/models.py +0 -0
  99. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/protocol/packets.py +0 -0
  100. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/protocol/protocol_types.py +0 -0
  101. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/protocol/serializer.py +0 -0
  102. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/py.typed +0 -0
  103. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/theme/__init__.py +0 -0
  104. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/theme/canvas.py +0 -0
  105. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/theme/generators.py +0 -0
  106. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/theme/library.py +0 -0
  107. {lifx_async-4.8.0 → lifx_async-4.8.1}/src/lifx/theme/theme.py +0 -0
  108. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/__init__.py +0 -0
  109. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/conftest.py +0 -0
  110. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_api/__init__.py +0 -0
  111. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_api/test_api_apply_theme.py +0 -0
  112. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_api/test_api_batch_errors.py +0 -0
  113. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_api/test_api_batch_operations.py +0 -0
  114. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_api/test_api_discovery.py +0 -0
  115. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_api/test_api_organization.py +0 -0
  116. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_color.py +0 -0
  117. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_devices/__init__.py +0 -0
  118. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_devices/conftest.py +0 -0
  119. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_devices/test_base.py +0 -0
  120. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_devices/test_ceiling.py +0 -0
  121. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_devices/test_hev.py +0 -0
  122. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_devices/test_infrared.py +0 -0
  123. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_devices/test_light.py +0 -0
  124. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_devices/test_mac_address.py +0 -0
  125. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_devices/test_matrix.py +0 -0
  126. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_devices/test_multizone.py +0 -0
  127. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_devices/test_state_ceiling.py +0 -0
  128. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_devices/test_state_hev.py +0 -0
  129. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_devices/test_state_infrared.py +0 -0
  130. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_devices/test_state_light.py +0 -0
  131. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_devices/test_state_management.py +0 -0
  132. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_devices/test_state_matrix.py +0 -0
  133. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_devices/test_state_multizone.py +0 -0
  134. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_effects/__init__.py +0 -0
  135. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_effects/test_base.py +0 -0
  136. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_effects/test_capability_filtering.py +0 -0
  137. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_effects/test_colorloop.py +0 -0
  138. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_effects/test_integration.py +0 -0
  139. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_effects/test_models.py +0 -0
  140. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_effects/test_pulse.py +0 -0
  141. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_effects/test_state_manager.py +0 -0
  142. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_network/__init__.py +0 -0
  143. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_network/test_concurrent_requests.py +0 -0
  144. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_network/test_connection.py +0 -0
  145. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_network/test_discovery_devices.py +0 -0
  146. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_network/test_discovery_errors.py +0 -0
  147. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_network/test_mdns/__init__.py +0 -0
  148. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_network/test_mdns/conftest.py +0 -0
  149. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_network/test_mdns/test_discovery.py +0 -0
  150. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_network/test_mdns/test_dns.py +0 -0
  151. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_network/test_mdns/test_transport.py +0 -0
  152. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_network/test_message.py +0 -0
  153. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_network/test_message_advanced.py +0 -0
  154. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_network/test_transport.py +0 -0
  155. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_products/test_product_generator.py +0 -0
  156. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_products/test_registry.py +0 -0
  157. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_protocol/test_generated.py +0 -0
  158. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_protocol/test_header.py +0 -0
  159. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_protocol/test_protocol_generator.py +0 -0
  160. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_protocol/test_serializer.py +0 -0
  161. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_theme/__init__.py +0 -0
  162. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_theme/conftest.py +0 -0
  163. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_theme/test_apply_theme.py +0 -0
  164. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_theme/test_canvas.py +0 -0
  165. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_theme/test_generators.py +0 -0
  166. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_theme/test_library.py +0 -0
  167. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_theme/test_theme.py +0 -0
  168. {lifx_async-4.8.0 → lifx_async-4.8.1}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lifx-async
3
- Version: 4.8.0
3
+ Version: 4.8.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>
@@ -2,6 +2,14 @@
2
2
 
3
3
  <!-- version list -->
4
4
 
5
+ ## v4.8.1 (2025-12-24)
6
+
7
+ ### Bug Fixes
8
+
9
+ - Tighten up the URL parsing to be even more specific
10
+ ([`0222362`](https://github.com/Djelibeybi/lifx-async/commit/0222362ace8d7c8bbbe7d5a50f9fb21b7cb89cd5))
11
+
12
+
5
13
  ## v4.8.0 (2025-12-20)
6
14
 
7
15
  ### Features
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lifx-async"
3
- version = "4.8.0"
3
+ version = "4.8.1"
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"
@@ -16,7 +16,7 @@ from urllib.request import urlopen
16
16
  from lifx.const import PRODUCTS_URL
17
17
 
18
18
 
19
- def download_products() -> dict[str, Any] | list[dict[str, Any]]:
19
+ def download_products() -> dict[str, Any] | list[dict[str, Any]] | None:
20
20
  """Download and parse products.json from LIFX GitHub repository.
21
21
 
22
22
  Returns:
@@ -27,11 +27,13 @@ def download_products() -> dict[str, Any] | list[dict[str, Any]]:
27
27
  json.JSONDecodeError: If parsing fails
28
28
  """
29
29
  parsed_url = urlparse(PRODUCTS_URL)
30
- if parsed_url.scheme == "https" and parsed_url.netloc.startswith(
31
- "raw.githubusercontent.com"
30
+ if (
31
+ parsed_url.scheme == "https"
32
+ and parsed_url.netloc == "raw.githubusercontent.com"
33
+ and parsed_url.path.startswith("/LIFX/")
32
34
  ):
33
- print(f"Downloading products.json from {PRODUCTS_URL}...")
34
- with urlopen(PRODUCTS_URL) as response: # nosec B310
35
+ print(f"Downloading products.json from {parsed_url.geturl()}...")
36
+ with urlopen(parsed_url.geturl()) as response: # nosec B310
35
37
  products_data = response.read()
36
38
 
37
39
  print("Parsing products specification...")
@@ -1397,7 +1397,7 @@ from lifx.protocol.base import Packet
1397
1397
  return code
1398
1398
 
1399
1399
 
1400
- def download_protocol() -> dict[str, Any]:
1400
+ def download_protocol() -> dict[str, Any] | None:
1401
1401
  """Download and parse protocol.yml from LIFX GitHub repository.
1402
1402
 
1403
1403
  Returns:
@@ -1408,11 +1408,13 @@ def download_protocol() -> dict[str, Any]:
1408
1408
  yaml.YAMLError: If parsing fails
1409
1409
  """
1410
1410
  parsed_url = urlparse(PROTOCOL_URL)
1411
- if parsed_url.scheme == "https" and parsed_url.netloc.startswith(
1412
- "raw.githubusercontent.com"
1411
+ if (
1412
+ parsed_url.scheme == "https"
1413
+ and parsed_url.netloc == "raw.githubusercontent.com"
1414
+ and parsed_url.path.startswith("/LIFX/")
1413
1415
  ):
1414
- print(f"Downloading protocol.yml from {PROTOCOL_URL}...")
1415
- with urlopen(PROTOCOL_URL) as response: # nosec B310
1416
+ print(f"Downloading protocol.yml from {parsed_url.geturl()}...")
1417
+ with urlopen(parsed_url.geturl()) as response: # nosec B310
1416
1418
  protocol_data = response.read()
1417
1419
 
1418
1420
  print("Parsing protocol specification...")
@@ -337,7 +337,7 @@ wheels = [
337
337
 
338
338
  [[package]]
339
339
  name = "lifx-async"
340
- version = "4.8.0"
340
+ version = "4.8.1"
341
341
  source = { editable = "." }
342
342
 
343
343
  [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
File without changes