benchlab-pytools 3.0.0__tar.gz → 3.0.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 (207) hide show
  1. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/CHANGELOG.md +28 -0
  2. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/CONTRIBUTING.md +1 -1
  3. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/PKG-INFO +20 -3
  4. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/README.md +18 -2
  5. benchlab_pytools-3.0.2/benchlab/__init__.py +5 -0
  6. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2/benchlab}/bootstrap.py +0 -1
  7. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/config/config_client.py +3 -4
  8. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/config/config_manager.py +5 -6
  9. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/core/datasource.py +4 -7
  10. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/core/datasource_manager.py +6 -7
  11. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/core/infrastructure.py +6 -8
  12. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/core/process_manager.py +1 -2
  13. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/core/statistics.py +3 -4
  14. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/csv_log/csv_logger_enhanced.py +2 -4
  15. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/csv_log/message_batcher.py +2 -5
  16. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/csv_log/smart_retry.py +6 -8
  17. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/graph/app.py +9 -6
  18. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/hwinfo/hwinfo_export.py +4 -6
  19. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/link/link_main.py +3 -5
  20. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/menu.py +1 -1
  21. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/menu_classic.py +1 -1
  22. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2/benchlab}/requirements.txt +4 -1
  23. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/sources.py +1 -6
  24. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/tools.py +1 -1
  25. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/tui/tui_core.py +27 -44
  26. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/tui/tui_main.py +9 -14
  27. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/vu_server_manager.py +2 -4
  28. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/vu_tui.py +25 -32
  29. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/vu_updater.py +3 -3
  30. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/wigidash/benchlab_fleet.py +2 -2
  31. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/wigidash/benchlab_graph.py +3 -4
  32. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/wigidash/wigidash_device.py +2 -2
  33. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/wigidash/wigidash_manager.py +3 -6
  34. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/wigidash/wigidash_session.py +16 -22
  35. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/wigidash/wigidash_usb.py +6 -10
  36. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/wigidash/wigidash_widget.py +2 -4
  37. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab.py +5 -2
  38. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/pyproject.toml +1 -0
  39. benchlab_pytools-3.0.0/benchlab/__init__.py +0 -14
  40. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/.flake8 +0 -0
  41. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/.gitignore +0 -0
  42. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/LICENSE +0 -0
  43. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/__main__.py +0 -0
  44. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/config/README.md +0 -0
  45. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/config/__init__.py +0 -0
  46. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/config/config_tool.py +0 -0
  47. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/config/diff.py +0 -0
  48. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/config/examples/complete_config.json +0 -0
  49. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/config/examples/rgb_lighting.json +0 -0
  50. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/config/examples/simple_fan.json +0 -0
  51. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/config/schema.py +0 -0
  52. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/config/test_config_client.py +0 -0
  53. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/config/test_config_manager.py +0 -0
  54. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/config/test_diff.py +0 -0
  55. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/core/README.md +0 -0
  56. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/core/__init__.py +0 -0
  57. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/core/config.py +0 -0
  58. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/core/device_registry.py +0 -0
  59. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/core/discovery.py +0 -0
  60. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/core/retry.py +0 -0
  61. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/core/shared_serial.py +0 -0
  62. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/csv_log/README.md +0 -0
  63. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/csv_log/__init__.py +0 -0
  64. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/csv_log/requirements.txt +0 -0
  65. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/graph/README.md +0 -0
  66. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/graph/__init__.py +0 -0
  67. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/graph/requirements.txt +0 -0
  68. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/graph/runner.py +0 -0
  69. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/graph/test_graph.py +0 -0
  70. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/graph/ui.py +0 -0
  71. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/hwinfo/README.md +0 -0
  72. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/hwinfo/__init__.py +0 -0
  73. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/hwinfo/requirements.txt +0 -0
  74. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/hwinfo/test_hwinfo_export.py +0 -0
  75. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/launcher.py +0 -0
  76. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/link/.env.EXAMPLE +0 -0
  77. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/link/README.md +0 -0
  78. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/link/__init__.py +0 -0
  79. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/link/test_link_main.py +0 -0
  80. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/main.py +0 -0
  81. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/mqtt/README.md +0 -0
  82. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/mqtt/__init__.py +0 -0
  83. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/mqtt/mqtt.config_template +0 -0
  84. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/mqtt/mqtt_publisher.py +0 -0
  85. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/mqtt/requirements.txt +0 -0
  86. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/mqtt/test_mqtt_publisher.py +0 -0
  87. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/prefs.py +0 -0
  88. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/restapi/.env.example +0 -0
  89. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/restapi/__init__.py +0 -0
  90. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/restapi/favicon.ico +0 -0
  91. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/restapi/readme.md +0 -0
  92. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/restapi/requirements.txt +0 -0
  93. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/restapi/telemetry_api.py +0 -0
  94. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/restapi/test_server.py +0 -0
  95. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/tui/README.md +0 -0
  96. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/tui/__init__.py +0 -0
  97. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/tui/config.py +0 -0
  98. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/tui/requirements.txt +0 -0
  99. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/tui/test_tui_core.py +0 -0
  100. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/tui/test_tui_main.py +0 -0
  101. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/README.md +0 -0
  102. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/NOTICE.md +0 -0
  103. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/README.md +0 -0
  104. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/Running_from_source_on_linux.md +0 -0
  105. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/__init__.py +0 -0
  106. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/assets/vu1_hello_world.png +0 -0
  107. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/community_applications.md +0 -0
  108. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/config.yaml +0 -0
  109. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/database.py +0 -0
  110. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/dial_driver.py +0 -0
  111. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/dials/Comms_Hub_Gauge.py +0 -0
  112. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/dials/Comms_Hub_Server.py +0 -0
  113. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/dials/__init__.py +0 -0
  114. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/dials/base_logger.py +0 -0
  115. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/installer/inc/icon.ico +0 -0
  116. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/installer/install.nsi +0 -0
  117. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/make_version.py +0 -0
  118. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/pylintrc +0 -0
  119. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/requirements.txt +0 -0
  120. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/serial_driver.py +0 -0
  121. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/server.py +0 -0
  122. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/server_config.py +0 -0
  123. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/server_dial_handler.py +0 -0
  124. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/vu_notifications.py +0 -0
  125. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/android-chrome-192x192.png +0 -0
  126. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/android-chrome-512x512.png +0 -0
  127. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/apple-touch-icon.png +0 -0
  128. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/demo.css +0 -0
  129. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/demo.min.css +0 -0
  130. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/demo.rtl.css +0 -0
  131. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/demo.rtl.min.css +0 -0
  132. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-flags.css +0 -0
  133. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-flags.min.css +0 -0
  134. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-flags.rtl.css +0 -0
  135. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-flags.rtl.min.css +0 -0
  136. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-payments.css +0 -0
  137. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-payments.min.css +0 -0
  138. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-payments.rtl.css +0 -0
  139. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-payments.rtl.min.css +0 -0
  140. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-social.css +0 -0
  141. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-social.min.css +0 -0
  142. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-social.rtl.css +0 -0
  143. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-social.rtl.min.css +0 -0
  144. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-vendors.css +0 -0
  145. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-vendors.min.css +0 -0
  146. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-vendors.rtl.css +0 -0
  147. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-vendors.rtl.min.css +0 -0
  148. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler.css +0 -0
  149. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler.min.css +0 -0
  150. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler.rtl.css +0 -0
  151. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler.rtl.min.css +0 -0
  152. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/theme.min.css +0 -0
  153. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/img/header.png +0 -0
  154. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/img/logo.png +0 -0
  155. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/dark-theme.js +0 -0
  156. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/dark-theme.min.js +0 -0
  157. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/demo.js +0 -0
  158. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/demo.min.js +0 -0
  159. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/jquery.min.js +0 -0
  160. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/tabler.esm.js +0 -0
  161. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/tabler.esm.min.js +0 -0
  162. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/tabler.js +0 -0
  163. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/tabler.min.js +0 -0
  164. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/vu1_api.js +0 -0
  165. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/vu1_gui_api_key_settings.js +0 -0
  166. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/vu1_gui_api_keys.js +0 -0
  167. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/vu1_gui_dial.js +0 -0
  168. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/vu1_gui_home.js +0 -0
  169. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/vu1_gui_root.js +0 -0
  170. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/favicon-16x16.png +0 -0
  171. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/favicon-32x32.png +0 -0
  172. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/favicon.ico +0 -0
  173. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/favicon.png +0 -0
  174. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/index.html +0 -0
  175. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/views/api_keys.html +0 -0
  176. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/views/dial.html +0 -0
  177. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/views/footer.html +0 -0
  178. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/views/header.html +0 -0
  179. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/views/key_settings.html +0 -0
  180. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/views/start.html +0 -0
  181. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/__init__.py +0 -0
  182. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/assets/Barlow-Bold.ttf +0 -0
  183. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/assets/bl_dial_144x200.png +0 -0
  184. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/assets/bl_logo_144x200.png +0 -0
  185. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/devices.py +0 -0
  186. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/requirements.txt +0 -0
  187. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/sensors.py +0 -0
  188. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/test_devices.py +0 -0
  189. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/test_vu_server_config.py +0 -0
  190. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/test_vu_server_manager.py +0 -0
  191. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/test_vu_tui.py +0 -0
  192. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/vu_dial.config_template +0 -0
  193. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/vu_logo_gen.py +0 -0
  194. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/vu_server.config_template +0 -0
  195. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/vu/vu_server_config.py +0 -0
  196. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/wigidash/README.md +0 -0
  197. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/wigidash/__init__.py +0 -0
  198. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/wigidash/assets/Inter-Bold.ttf +0 -0
  199. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/wigidash/assets/Inter.ttf +0 -0
  200. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/wigidash/assets/benchlab.png +0 -0
  201. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/wigidash/benchlab_overview.py +0 -0
  202. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/wigidash/benchlab_telemetry.py +0 -0
  203. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/wigidash/benchlab_ui.py +0 -0
  204. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/wigidash/benchlab_utils.py +0 -0
  205. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/wigidash/requirements.txt +0 -0
  206. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/benchlab/wigidash/test_wigidash.py +0 -0
  207. {benchlab_pytools-3.0.0 → benchlab_pytools-3.0.2}/pytest.ini +0 -0
@@ -4,6 +4,32 @@ All notable changes to BENCHLAB PyTools are documented here. Format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows
5
5
  [SemVer](https://semver.org/).
6
6
 
7
+ ## [3.0.2] - 2026-08-18
8
+
9
+ ### Fixed
10
+ - Several f-strings had their `{...}` expression split across a line
11
+ break, which is [PEP 701](https://peps.python.org/pep-0701/) syntax
12
+ only valid on Python 3.12+. Despite `requires-python = ">=3.10"`, this
13
+ raised `SyntaxError` immediately on 3.10/3.11 (e.g. `benchlab -tui`
14
+ failing with `SyntaxError: unterminated string literal` in
15
+ `benchlab/core/datasource.py`) — invisible in CI since every workflow
16
+ pins Python 3.13. Collapsed all such f-strings back onto single lines
17
+ across 27 files.
18
+
19
+ ## [3.0.1] - 2026-08-18
20
+
21
+ ### Fixed
22
+ - PyPI install was broken: `bootstrap.py` and the core `requirements.txt`
23
+ lived at the repo root and were never included in the wheel (only
24
+ `benchlab/` is packaged), so `pip install benchlab-pytools` followed by
25
+ `benchlab ...` failed with `ModuleNotFoundError: No module named
26
+ 'bootstrap'`. Both files moved into `benchlab/`, with internal imports
27
+ updated to relative imports.
28
+ - `pywin32` was missing from `pyproject.toml`'s core dependencies, so
29
+ PyPI installs on Windows did not pull it in despite the `named_pipe`
30
+ data source depending on it. Added `pywin32>=306; platform_system ==
31
+ 'Windows'` alongside the existing `windows-curses` entry.
32
+
7
33
  ## [3.0.0] - 2026-08-15
8
34
 
9
35
  ### Added
@@ -41,4 +67,6 @@ export, MQTT publisher, VU dials, WigiDash, and config import/export tools,
41
67
  sharing a common data-source layer (direct serial, FastAPI, MQTT, named
42
68
  pipe, service HTTP).
43
69
 
70
+ [3.0.2]: https://github.com/BenchLab-io/benchlab-pytools/compare/v3.0.1...v3.0.2
71
+ [3.0.1]: https://github.com/BenchLab-io/benchlab-pytools/compare/v3.0.0...v3.0.1
44
72
  [3.0.0]: https://github.com/BenchLab-io/benchlab-pytools/compare/v0.8.2...v3.0.0
@@ -5,7 +5,7 @@
5
5
  ```bash
6
6
  git clone https://github.com/BenchLab-io/benchlab-pytools.git
7
7
  cd benchlab-pytools
8
- pip install -r requirements.txt
8
+ pip install -r benchlab/requirements.txt
9
9
  pip install -r benchlab/csv_log/requirements.txt
10
10
  pip install -r benchlab/graph/requirements.txt
11
11
  pip install -r benchlab/wigidash/requirements.txt
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: benchlab-pytools
3
- Version: 3.0.0
3
+ Version: 3.0.2
4
4
  Summary: Python control suite for BENCHLAB telemetry devices
5
5
  Project-URL: Homepage, https://benchlab.io/
6
6
  Project-URL: Repository, https://github.com/BenchLab-io/benchlab-pytools
@@ -25,6 +25,7 @@ Requires-Python: >=3.10
25
25
  Requires-Dist: benchlab-pycore>=0.5.1
26
26
  Requires-Dist: packaging<26.0,>=23.0
27
27
  Requires-Dist: python-dotenv<2.0,>=1.0.0
28
+ Requires-Dist: pywin32>=306; platform_system == 'Windows'
28
29
  Requires-Dist: textual<9.0,>=0.60
29
30
  Requires-Dist: windows-curses>=2.4.1; platform_system == 'Windows'
30
31
  Provides-Extra: all
@@ -111,8 +112,18 @@ All tools share a common data-source layer, so the same telemetry can be read di
111
112
 
112
113
  Requires Python 3.10+.
113
114
 
115
+ ### From PyPI
116
+
117
+ ```bash
118
+ pip install benchlab-pytools
119
+ ```
120
+
121
+ This installs a `benchlab` console command on your PATH (see [Command-Line Flags](#command-line-flags) below). Install with extras for the tools you need, e.g. `pip install "benchlab-pytools[tui]"`.
122
+
123
+ ### From source
124
+
114
125
  ```bash
115
- pip install -r requirements.txt
126
+ pip install -r benchlab/requirements.txt
116
127
  ```
117
128
 
118
129
  Each tool has its own `requirements.txt` (e.g. `benchlab/graph/requirements.txt`, `benchlab/vu/requirements.txt`). The launcher installs a tool's requirements automatically the first time it's run — you generally don't need to install them by hand.
@@ -135,11 +146,17 @@ or equivalently:
135
146
  python -m benchlab
136
147
  ```
137
148
 
149
+ If installed from PyPI, use the `benchlab` command instead:
150
+
151
+ ```bash
152
+ benchlab
153
+ ```
154
+
138
155
  The interactive menu (prompt_toolkit-based, with a plain-input fallback if `prompt_toolkit` isn't installed) lets you pick a data source and one or more tools, then launches them — installing any missing per-tool dependencies along the way.
139
156
 
140
157
  ### Command-Line Flags
141
158
 
142
- Each tool can also be launched directly with a flag:
159
+ Each tool can also be launched directly with a flag. If installed from PyPI, replace `python -m benchlab` with `benchlab` in the examples below (e.g. `benchlab -tui`).
143
160
 
144
161
  ```bash
145
162
  python -m benchlab -tui # Interactive terminal dashboard
@@ -21,8 +21,18 @@ All tools share a common data-source layer, so the same telemetry can be read di
21
21
 
22
22
  Requires Python 3.10+.
23
23
 
24
+ ### From PyPI
25
+
26
+ ```bash
27
+ pip install benchlab-pytools
28
+ ```
29
+
30
+ This installs a `benchlab` console command on your PATH (see [Command-Line Flags](#command-line-flags) below). Install with extras for the tools you need, e.g. `pip install "benchlab-pytools[tui]"`.
31
+
32
+ ### From source
33
+
24
34
  ```bash
25
- pip install -r requirements.txt
35
+ pip install -r benchlab/requirements.txt
26
36
  ```
27
37
 
28
38
  Each tool has its own `requirements.txt` (e.g. `benchlab/graph/requirements.txt`, `benchlab/vu/requirements.txt`). The launcher installs a tool's requirements automatically the first time it's run — you generally don't need to install them by hand.
@@ -45,11 +55,17 @@ or equivalently:
45
55
  python -m benchlab
46
56
  ```
47
57
 
58
+ If installed from PyPI, use the `benchlab` command instead:
59
+
60
+ ```bash
61
+ benchlab
62
+ ```
63
+
48
64
  The interactive menu (prompt_toolkit-based, with a plain-input fallback if `prompt_toolkit` isn't installed) lets you pick a data source and one or more tools, then launches them — installing any missing per-tool dependencies along the way.
49
65
 
50
66
  ### Command-Line Flags
51
67
 
52
- Each tool can also be launched directly with a flag:
68
+ Each tool can also be launched directly with a flag. If installed from PyPI, replace `python -m benchlab` with `benchlab` in the examples below (e.g. `benchlab -tui`).
53
69
 
54
70
  ```bash
55
71
  python -m benchlab -tui # Interactive terminal dashboard
@@ -0,0 +1,5 @@
1
+ """
2
+ BENCHLAB Telemetry Package
3
+ """
4
+
5
+ __version__ = "3.0.2"
@@ -149,7 +149,6 @@ def install_core_requirements():
149
149
  req_file = BASE_DIR / "requirements.txt"
150
150
 
151
151
  if not req_file.exists():
152
- logger.warning("No global requirements.txt found")
153
152
  return
154
153
 
155
154
  install_requirements_file(str(req_file), "CORE")
@@ -177,8 +177,8 @@ class DirectConfigClient(ConfigClient):
177
177
 
178
178
  self.product_id = info.get('ProductId')
179
179
  logger.info(
180
- f"Connected to device on {port}, Product ID: 0x{
181
- self.product_id:02X}")
180
+ f"Connected to device on {port}, "
181
+ f"Product ID: 0x{self.product_id:02X}")
182
182
 
183
183
  def get_device_info(self) -> Optional[Dict[str, Any]]:
184
184
  """Get device information."""
@@ -465,8 +465,7 @@ class NamedPipeConfigClient(ConfigClient):
465
465
  win32pipe.WaitNamedPipe(path, 5000)
466
466
  except pywintypes.error as e:
467
467
  raise ConnectionError(
468
- f"Pipe '{
469
- self.pipe_name}' not available: {e}") from e
468
+ f"Pipe '{self.pipe_name}' not available: {e}") from e
470
469
 
471
470
  self.handle = win32file.CreateFile(
472
471
  path,
@@ -55,8 +55,7 @@ class ConfigManager:
55
55
  from benchlab_pycore.core import get_fleet_info
56
56
  devices = get_fleet_info()
57
57
  logger.info(
58
- f"Discovered {
59
- len(devices)} device(s) via direct serial")
58
+ f"Discovered {len(devices)} device(s) via direct serial")
60
59
  return devices
61
60
  except Exception as e:
62
61
  logger.error(f"Failed to discover direct devices: {e}")
@@ -357,8 +356,8 @@ class ConfigManager:
357
356
  device_config.selector.model_dump(), devices)
358
357
  if not identifier:
359
358
  logger.error(
360
- f"Device not found matching selector: {
361
- device_config.selector}")
359
+ "Device not found matching selector: "
360
+ f"{device_config.selector}")
362
361
  continue
363
362
 
364
363
  logger.info(f"Selected: {identifier}")
@@ -453,8 +452,8 @@ class ConfigManager:
453
452
  if not client.write_fan_config(
454
453
  profile.profileId, fan_id, fan_dict):
455
454
  logger.error(
456
- f"Failed to write fan config {
457
- profile.profileId}/{fan_id}")
455
+ "Failed to write fan config "
456
+ f"{profile.profileId}/{fan_id}")
458
457
  success = False
459
458
 
460
459
  # Apply RGB profiles
@@ -372,8 +372,7 @@ class FastAPIDataSource(DataSource):
372
372
  return True
373
373
  else:
374
374
  logger.error(
375
- f"FastAPI health check returned {
376
- response.status_code}")
375
+ f"FastAPI health check returned {response.status_code}")
377
376
  except Exception as e:
378
377
  logger.error(f"Failed to connect to FastAPI server: {e}")
379
378
 
@@ -1025,9 +1024,8 @@ class ServiceHttpDataSource(DataSource):
1025
1024
 
1026
1025
  if resp.status_code != 200:
1027
1026
  logger.error(
1028
- f"BenchLab service health check failed (HTTP {
1029
- resp.status_code}) " f"at {
1030
- self.base_url}/health")
1027
+ f"BenchLab service health check failed "
1028
+ f"(HTTP {resp.status_code}) at {self.base_url}/health")
1031
1029
  return False
1032
1030
 
1033
1031
  # Fetch initial device list
@@ -1051,8 +1049,7 @@ class ServiceHttpDataSource(DataSource):
1051
1049
  target=self._worker_loop, daemon=True)
1052
1050
  self._worker_thread.start()
1053
1051
  logger.info(
1054
- f"Connected to BenchLab service HTTP API at {
1055
- self.base_url}")
1052
+ f"Connected to BenchLab service HTTP API at {self.base_url}")
1056
1053
  return True
1057
1054
 
1058
1055
  def disconnect(self) -> None:
@@ -109,14 +109,14 @@ class DataSourceManager:
109
109
  self._datasource = create_datasource(self.source_type, **kwargs)
110
110
 
111
111
  if not self._datasource.connect():
112
- self._last_error = f"Failed to connect to {
113
- self.source_type} datasource"
112
+ self._last_error = (
113
+ f"Failed to connect to {self.source_type} datasource")
114
114
  return False
115
115
 
116
116
  devices = self._datasource.list_devices()
117
117
  if not devices:
118
- self._last_error = f"No devices available via {
119
- self.source_type}"
118
+ self._last_error = (
119
+ f"No devices available via {self.source_type}")
120
120
  return False
121
121
 
122
122
  if uid and any(d.get('uid') == uid for d in devices):
@@ -153,9 +153,8 @@ class DataSourceManager:
153
153
  self._worker_thread.start()
154
154
 
155
155
  logger.info(
156
- f"Connected to {
157
- self.source_type} datasource, selected device: {
158
- self._selected_uid}")
156
+ f"Connected to {self.source_type} datasource, "
157
+ f"selected device: {self._selected_uid}")
159
158
  return True
160
159
 
161
160
  except Exception as e:
@@ -80,9 +80,8 @@ class InfrastructureManager:
80
80
  return True
81
81
 
82
82
  logger.info(
83
- f"Starting FastAPI server on {
84
- self.fastapi_host}:{
85
- self.fastapi_port}")
83
+ f"Starting FastAPI server on "
84
+ f"{self.fastapi_host}:{self.fastapi_port}")
86
85
 
87
86
  try:
88
87
  # Start FastAPI server as subprocess
@@ -107,8 +106,8 @@ class InfrastructureManager:
107
106
  if self._wait_for_port(
108
107
  self.fastapi_host, self.fastapi_port, timeout):
109
108
  logger.info(
110
- f"FastAPI server started on port {
111
- self.fastapi_port}")
109
+ "FastAPI server started on port "
110
+ f"{self.fastapi_port}")
112
111
  return True
113
112
  else:
114
113
  logger.error("FastAPI server failed to start")
@@ -171,9 +170,8 @@ class InfrastructureManager:
171
170
  return True
172
171
 
173
172
  logger.info(
174
- f"Starting MQTT publisher to {
175
- self.mqtt_broker}:{
176
- self.mqtt_port}")
173
+ f"Starting MQTT publisher to "
174
+ f"{self.mqtt_broker}:{self.mqtt_port}")
177
175
 
178
176
  try:
179
177
  self._stop_event.clear()
@@ -248,8 +248,7 @@ class ProcessManager:
248
248
  os.path.abspath(__file__)),
249
249
  "..",
250
250
  "logs",
251
- f"svc_{
252
- mp.name}")
251
+ f"svc_{mp.name}")
253
252
  with open(f"{log_base}_stderr.log", "r",
254
253
  encoding="utf-8") as f:
255
254
  mp.stderr_log = f.read()
@@ -202,10 +202,9 @@ class StatsFormatter:
202
202
  if min_val is None or max_val is None or avg_val is None:
203
203
  return ""
204
204
 
205
- return f"{
206
- min_val:.{decimals}f}-{
207
- max_val:.{decimals}f} ~{
208
- avg_val:.{decimals}f}{unit}"
205
+ return (
206
+ f"{min_val:.{decimals}f}-{max_val:.{decimals}f} "
207
+ f"~{avg_val:.{decimals}f}{unit}")
209
208
 
210
209
 
211
210
  # Convenience function for creating a stats callback
@@ -141,10 +141,8 @@ class EnhancedCSVLogger:
141
141
  print("\n--- Available Devices ---")
142
142
  for i, dev in enumerate(devices, 1):
143
143
  print(
144
- f" {i}: Port: {
145
- dev.port:<12} UID: {
146
- dev.uid} FW: {
147
- dev.firmware}")
144
+ f" {i}: Port: {dev.port:<12} UID: {dev.uid} "
145
+ f"FW: {dev.firmware}")
148
146
 
149
147
  selection = input(
150
148
  "\nEnter device numbers (comma-separated), 'all', "
@@ -95,9 +95,7 @@ class MessageBatcher:
95
95
  (self.metrics.avg_flush_time * (n - 1) + elapsed) / n
96
96
  )
97
97
  self.logger.debug(
98
- f"Flushed {
99
- len(messages_to_flush)} messages in {
100
- elapsed:.3f}s")
98
+ f"Flushed {len(messages_to_flush)} messages in {elapsed:.3f}s")
101
99
  return True
102
100
 
103
101
  except Exception as e:
@@ -222,8 +220,7 @@ class CSVBatchWriter:
222
220
  elif self.format == "json":
223
221
  self._write_json_batch(file_info, messages_to_write)
224
222
  self.logger.debug(
225
- f"Wrote {
226
- len(messages_to_write)} rows for {uid}")
223
+ f"Wrote {len(messages_to_write)} rows for {uid}")
227
224
  except Exception as e:
228
225
  self.logger.error(f"Failed to write batch for {uid}: {e}")
229
226
  buf.extend(messages_to_write) # restore on failure
@@ -104,8 +104,8 @@ class CircuitBreaker:
104
104
  if (self.config.circuit_breaker_enabled and
105
105
  self.failure_count >= self.config.circuit_failure_threshold):
106
106
  self.logger.warning(
107
- f"Circuit breaker: opening after {
108
- self.failure_count} failures")
107
+ "Circuit breaker: opening after "
108
+ f"{self.failure_count} failures")
109
109
  self.state = CircuitState.OPEN
110
110
 
111
111
 
@@ -144,9 +144,8 @@ class SmartRetryManager:
144
144
 
145
145
  if attempt == self.config.max_retries:
146
146
  self.logger.error(
147
- f"Max retries ({
148
- self.config.max_retries}) exceeded for {
149
- func.__name__}")
147
+ f"Max retries ({self.config.max_retries}) "
148
+ f"exceeded for {func.__name__}")
150
149
  raise e
151
150
 
152
151
  # Calculate delay
@@ -242,9 +241,8 @@ class AdaptiveRetryManager:
242
241
 
243
242
  if attempt == self.config.max_retries:
244
243
  self.logger.error(
245
- f"Max retries ({
246
- self.config.max_retries}) exceeded for {
247
- func.__name__}")
244
+ f"Max retries ({self.config.max_retries}) "
245
+ f"exceeded for {func.__name__}")
248
246
  raise e
249
247
 
250
248
  # Calculate adaptive delay
@@ -263,12 +263,15 @@ class GraphApp:
263
263
  min_y - margin, max_y + margin)
264
264
 
265
265
  s = self.session_stats
266
- min_text = f"Min: {
267
- s['min']:.2f}" if s["min"] is not None else "Min: --"
268
- max_text = f"Max: {
269
- s['max']:.2f}" if s["max"] is not None else "Max: --"
270
- avg_text = f"Avg: {
271
- s['avg']:.2f}" if s["avg"] is not None else "Avg: --"
266
+ min_text = (
267
+ f"Min: {s['min']:.2f}"
268
+ if s["min"] is not None else "Min: --")
269
+ max_text = (
270
+ f"Max: {s['max']:.2f}"
271
+ if s["max"] is not None else "Max: --")
272
+ avg_text = (
273
+ f"Avg: {s['avg']:.2f}"
274
+ if s["avg"] is not None else "Avg: --")
272
275
  for tag, text in (
273
276
  ("graph_min", min_text),
274
277
  ("graph_min_float", min_text),
@@ -71,8 +71,7 @@ def write_hwinfo_sensor(device_name, sensor_type, idx, name, value, unit=None):
71
71
  # Write Value
72
72
  if isinstance(value, float):
73
73
  winreg.SetValueEx(
74
- key, "Value", 0, winreg.REG_SZ, f"{
75
- value:.3f}")
74
+ key, "Value", 0, winreg.REG_SZ, f"{value:.3f}")
76
75
  else:
77
76
  winreg.SetValueEx(key, "Value", 0, winreg.REG_SZ, str(value))
78
77
 
@@ -156,8 +155,7 @@ def _export_grouped(device_name: str, grouped_sensors: dict):
156
155
  write_hwinfo_sensor(device_name, group, idx, key, value, unit)
157
156
 
158
157
  summary = ", ".join(
159
- f"{k}: {
160
- len(v)}" for k,
158
+ f"{k}: {len(v)}" for k,
161
159
  v in grouped_sensors.items() if v)
162
160
  logger.debug("Device %s export summary: %s", device_name, summary)
163
161
 
@@ -308,8 +306,8 @@ def export_all_devices(update_interval=1, datasource=None):
308
306
  "HWiNFO export is only supported on Windows. "
309
307
  "Please run on a Windows system.")
310
308
  raise RuntimeError(
311
- f"HWiNFO export requires Windows. Current platform: {
312
- sys.platform}")
309
+ "HWiNFO export requires Windows. "
310
+ f"Current platform: {sys.platform}")
313
311
 
314
312
  # Remove only old BenchLab entries, not user-created sensors
315
313
  try:
@@ -217,8 +217,7 @@ class CloudMQTTClient:
217
217
  time.sleep(0.1)
218
218
  if not self._connected:
219
219
  logger.error(
220
- f"Timed out connecting to {host}:{
221
- self.cfg['port']}")
220
+ f"Timed out connecting to {host}:{self.cfg['port']}")
222
221
  return False
223
222
  logger.info(f"Connected to cloud broker {host}:{self.cfg['port']}")
224
223
  return True
@@ -229,9 +228,8 @@ class CloudMQTTClient:
229
228
  def reconnect(self) -> bool:
230
229
  """Attempt to reconnect using a fresh client."""
231
230
  logger.info(
232
- f"Reconnecting to cloud broker {
233
- self.cfg['host']}:{
234
- self.cfg['port']}...")
231
+ f"Reconnecting to cloud broker "
232
+ f"{self.cfg['host']}:{self.cfg['port']}...")
235
233
  try:
236
234
  self._client.loop_stop()
237
235
  except Exception:
@@ -23,7 +23,7 @@ import os
23
23
  import sys
24
24
  from typing import Dict, List, Optional, Tuple, Union
25
25
 
26
- from bootstrap import clear_screen
26
+ from .bootstrap import clear_screen
27
27
  from .tools import CONSUMER_TOOLS
28
28
  from .sources import (
29
29
  check_and_setup_source,
@@ -11,7 +11,7 @@ import os
11
11
  import sys
12
12
  from typing import List, Optional
13
13
 
14
- from bootstrap import clear_screen
14
+ from .bootstrap import clear_screen
15
15
  from .tools import CONSUMER_TOOLS
16
16
  from .sources import (
17
17
  check_and_setup_source,
@@ -22,4 +22,7 @@ paho-mqtt>=2.0,<3.0
22
22
  amqtt>=0.12.0,<0.13.0
23
23
 
24
24
  # Curses-based TUI
25
- windows-curses>=2.4.1; platform_system=="Windows"
25
+ windows-curses>=2.4.1; platform_system=="Windows"
26
+
27
+ # Named Pipe Data Source (BL_Service)
28
+ pywin32>=306; platform_system=="Windows"
@@ -145,12 +145,7 @@ import asyncio
145
145
  from amqtt.broker import Broker
146
146
 
147
147
  config = {{
148
- "listeners": {{
149
- "default": {{
150
- "type": "tcp",
151
- "bind": "0.0.0.0:{port}",
152
- }},
153
- }},
148
+ "listeners": {{"default": {{"type": "tcp", "bind": "0.0.0.0:{port}"}}}},
154
149
  "auth": {{"allow-anonymous": True}},
155
150
  "topic-check": {{"enabled": False}},
156
151
  }}
@@ -9,7 +9,7 @@ import importlib.util
9
9
  import logging
10
10
  from pathlib import Path
11
11
 
12
- from bootstrap import install_requirements_file
12
+ from .bootstrap import install_requirements_file
13
13
 
14
14
  logger = logging.getLogger("benchlab.launcher")
15
15