benchlab-pytools 3.0.1__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 (206) hide show
  1. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/CHANGELOG.md +13 -0
  2. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/PKG-INFO +1 -1
  3. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/__init__.py +1 -1
  4. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/config_client.py +3 -4
  5. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/config_manager.py +5 -6
  6. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/datasource.py +4 -7
  7. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/datasource_manager.py +6 -7
  8. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/infrastructure.py +6 -8
  9. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/process_manager.py +1 -2
  10. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/statistics.py +3 -4
  11. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/csv_log/csv_logger_enhanced.py +2 -4
  12. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/csv_log/message_batcher.py +2 -5
  13. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/csv_log/smart_retry.py +6 -8
  14. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/graph/app.py +9 -6
  15. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/hwinfo/hwinfo_export.py +4 -6
  16. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/link/link_main.py +3 -5
  17. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/sources.py +1 -6
  18. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/tui/tui_core.py +27 -44
  19. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/tui/tui_main.py +9 -14
  20. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/vu_server_manager.py +2 -4
  21. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/vu_tui.py +25 -32
  22. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/vu_updater.py +3 -3
  23. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/benchlab_fleet.py +2 -2
  24. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/benchlab_graph.py +3 -4
  25. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/wigidash_device.py +2 -2
  26. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/wigidash_manager.py +3 -6
  27. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/wigidash_session.py +16 -22
  28. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/wigidash_usb.py +6 -10
  29. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/wigidash_widget.py +2 -4
  30. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/.flake8 +0 -0
  31. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/.gitignore +0 -0
  32. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/CONTRIBUTING.md +0 -0
  33. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/LICENSE +0 -0
  34. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/README.md +0 -0
  35. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/__main__.py +0 -0
  36. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/bootstrap.py +0 -0
  37. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/README.md +0 -0
  38. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/__init__.py +0 -0
  39. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/config_tool.py +0 -0
  40. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/diff.py +0 -0
  41. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/examples/complete_config.json +0 -0
  42. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/examples/rgb_lighting.json +0 -0
  43. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/examples/simple_fan.json +0 -0
  44. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/schema.py +0 -0
  45. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/test_config_client.py +0 -0
  46. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/test_config_manager.py +0 -0
  47. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/test_diff.py +0 -0
  48. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/README.md +0 -0
  49. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/__init__.py +0 -0
  50. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/config.py +0 -0
  51. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/device_registry.py +0 -0
  52. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/discovery.py +0 -0
  53. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/retry.py +0 -0
  54. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/shared_serial.py +0 -0
  55. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/csv_log/README.md +0 -0
  56. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/csv_log/__init__.py +0 -0
  57. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/csv_log/requirements.txt +0 -0
  58. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/graph/README.md +0 -0
  59. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/graph/__init__.py +0 -0
  60. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/graph/requirements.txt +0 -0
  61. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/graph/runner.py +0 -0
  62. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/graph/test_graph.py +0 -0
  63. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/graph/ui.py +0 -0
  64. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/hwinfo/README.md +0 -0
  65. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/hwinfo/__init__.py +0 -0
  66. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/hwinfo/requirements.txt +0 -0
  67. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/hwinfo/test_hwinfo_export.py +0 -0
  68. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/launcher.py +0 -0
  69. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/link/.env.EXAMPLE +0 -0
  70. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/link/README.md +0 -0
  71. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/link/__init__.py +0 -0
  72. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/link/test_link_main.py +0 -0
  73. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/main.py +0 -0
  74. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/menu.py +0 -0
  75. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/menu_classic.py +0 -0
  76. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/mqtt/README.md +0 -0
  77. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/mqtt/__init__.py +0 -0
  78. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/mqtt/mqtt.config_template +0 -0
  79. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/mqtt/mqtt_publisher.py +0 -0
  80. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/mqtt/requirements.txt +0 -0
  81. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/mqtt/test_mqtt_publisher.py +0 -0
  82. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/prefs.py +0 -0
  83. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/requirements.txt +0 -0
  84. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/restapi/.env.example +0 -0
  85. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/restapi/__init__.py +0 -0
  86. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/restapi/favicon.ico +0 -0
  87. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/restapi/readme.md +0 -0
  88. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/restapi/requirements.txt +0 -0
  89. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/restapi/telemetry_api.py +0 -0
  90. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/restapi/test_server.py +0 -0
  91. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/tools.py +0 -0
  92. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/tui/README.md +0 -0
  93. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/tui/__init__.py +0 -0
  94. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/tui/config.py +0 -0
  95. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/tui/requirements.txt +0 -0
  96. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/tui/test_tui_core.py +0 -0
  97. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/tui/test_tui_main.py +0 -0
  98. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/README.md +0 -0
  99. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/NOTICE.md +0 -0
  100. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/README.md +0 -0
  101. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/Running_from_source_on_linux.md +0 -0
  102. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/__init__.py +0 -0
  103. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/assets/vu1_hello_world.png +0 -0
  104. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/community_applications.md +0 -0
  105. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/config.yaml +0 -0
  106. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/database.py +0 -0
  107. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/dial_driver.py +0 -0
  108. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/dials/Comms_Hub_Gauge.py +0 -0
  109. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/dials/Comms_Hub_Server.py +0 -0
  110. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/dials/__init__.py +0 -0
  111. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/dials/base_logger.py +0 -0
  112. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/installer/inc/icon.ico +0 -0
  113. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/installer/install.nsi +0 -0
  114. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/make_version.py +0 -0
  115. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/pylintrc +0 -0
  116. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/requirements.txt +0 -0
  117. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/serial_driver.py +0 -0
  118. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/server.py +0 -0
  119. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/server_config.py +0 -0
  120. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/server_dial_handler.py +0 -0
  121. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/vu_notifications.py +0 -0
  122. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/android-chrome-192x192.png +0 -0
  123. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/android-chrome-512x512.png +0 -0
  124. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/apple-touch-icon.png +0 -0
  125. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/demo.css +0 -0
  126. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/demo.min.css +0 -0
  127. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/demo.rtl.css +0 -0
  128. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/demo.rtl.min.css +0 -0
  129. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-flags.css +0 -0
  130. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-flags.min.css +0 -0
  131. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-flags.rtl.css +0 -0
  132. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-flags.rtl.min.css +0 -0
  133. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-payments.css +0 -0
  134. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-payments.min.css +0 -0
  135. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-payments.rtl.css +0 -0
  136. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-payments.rtl.min.css +0 -0
  137. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-social.css +0 -0
  138. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-social.min.css +0 -0
  139. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-social.rtl.css +0 -0
  140. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-social.rtl.min.css +0 -0
  141. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-vendors.css +0 -0
  142. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-vendors.min.css +0 -0
  143. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-vendors.rtl.css +0 -0
  144. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-vendors.rtl.min.css +0 -0
  145. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler.css +0 -0
  146. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler.min.css +0 -0
  147. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler.rtl.css +0 -0
  148. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler.rtl.min.css +0 -0
  149. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/theme.min.css +0 -0
  150. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/img/header.png +0 -0
  151. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/img/logo.png +0 -0
  152. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/dark-theme.js +0 -0
  153. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/dark-theme.min.js +0 -0
  154. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/demo.js +0 -0
  155. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/demo.min.js +0 -0
  156. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/jquery.min.js +0 -0
  157. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/tabler.esm.js +0 -0
  158. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/tabler.esm.min.js +0 -0
  159. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/tabler.js +0 -0
  160. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/tabler.min.js +0 -0
  161. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/vu1_api.js +0 -0
  162. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/vu1_gui_api_key_settings.js +0 -0
  163. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/vu1_gui_api_keys.js +0 -0
  164. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/vu1_gui_dial.js +0 -0
  165. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/vu1_gui_home.js +0 -0
  166. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/vu1_gui_root.js +0 -0
  167. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/favicon-16x16.png +0 -0
  168. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/favicon-32x32.png +0 -0
  169. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/favicon.ico +0 -0
  170. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/favicon.png +0 -0
  171. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/index.html +0 -0
  172. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/views/api_keys.html +0 -0
  173. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/views/dial.html +0 -0
  174. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/views/footer.html +0 -0
  175. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/views/header.html +0 -0
  176. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/views/key_settings.html +0 -0
  177. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/views/start.html +0 -0
  178. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/__init__.py +0 -0
  179. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/assets/Barlow-Bold.ttf +0 -0
  180. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/assets/bl_dial_144x200.png +0 -0
  181. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/assets/bl_logo_144x200.png +0 -0
  182. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/devices.py +0 -0
  183. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/requirements.txt +0 -0
  184. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/sensors.py +0 -0
  185. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/test_devices.py +0 -0
  186. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/test_vu_server_config.py +0 -0
  187. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/test_vu_server_manager.py +0 -0
  188. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/test_vu_tui.py +0 -0
  189. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/vu_dial.config_template +0 -0
  190. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/vu_logo_gen.py +0 -0
  191. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/vu_server.config_template +0 -0
  192. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/vu_server_config.py +0 -0
  193. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/README.md +0 -0
  194. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/__init__.py +0 -0
  195. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/assets/Inter-Bold.ttf +0 -0
  196. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/assets/Inter.ttf +0 -0
  197. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/assets/benchlab.png +0 -0
  198. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/benchlab_overview.py +0 -0
  199. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/benchlab_telemetry.py +0 -0
  200. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/benchlab_ui.py +0 -0
  201. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/benchlab_utils.py +0 -0
  202. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/requirements.txt +0 -0
  203. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/test_wigidash.py +0 -0
  204. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab.py +0 -0
  205. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/pyproject.toml +0 -0
  206. {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/pytest.ini +0 -0
@@ -4,6 +4,18 @@ 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
+
7
19
  ## [3.0.1] - 2026-08-18
8
20
 
9
21
  ### Fixed
@@ -55,5 +67,6 @@ export, MQTT publisher, VU dials, WigiDash, and config import/export tools,
55
67
  sharing a common data-source layer (direct serial, FastAPI, MQTT, named
56
68
  pipe, service HTTP).
57
69
 
70
+ [3.0.2]: https://github.com/BenchLab-io/benchlab-pytools/compare/v3.0.1...v3.0.2
58
71
  [3.0.1]: https://github.com/BenchLab-io/benchlab-pytools/compare/v3.0.0...v3.0.1
59
72
  [3.0.0]: https://github.com/BenchLab-io/benchlab-pytools/compare/v0.8.2...v3.0.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: benchlab-pytools
3
- Version: 3.0.1
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
@@ -2,4 +2,4 @@
2
2
  BENCHLAB Telemetry Package
3
3
  """
4
4
 
5
- __version__ = "3.0.1"
5
+ __version__ = "3.0.2"
@@ -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:
@@ -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
  }}
@@ -210,9 +210,9 @@ class TUICore:
210
210
 
211
211
  def _render_size_warning(self, width: int, height: int):
212
212
  msg = (
213
- f" Terminal too small ({width}x{height})" f" — resize to {
214
- Config.MIN_TERMINAL_COLS}x{
215
- Config.MIN_TERMINAL_ROWS} ")
213
+ f" Terminal too small ({width}x{height})"
214
+ f" — resize to "
215
+ f"{Config.MIN_TERMINAL_COLS}x{Config.MIN_TERMINAL_ROWS} ")
216
216
  try:
217
217
  self.stdscr.addstr(
218
218
  0, 0, msg[:width], # ← truncate, don't center
@@ -428,25 +428,17 @@ class TUICore:
428
428
  try:
429
429
  self.stdscr.addstr(6, cols['SEL'], f"{'':2}", hdr_attr)
430
430
  self.stdscr.addstr(
431
- 6, cols['MODEL'], f"{
432
- 'Model':<{
433
- widths['MODEL']}}", hdr_attr)
431
+ 6, cols['MODEL'],
432
+ f"{'Model':<{widths['MODEL']}}", hdr_attr)
434
433
  self.stdscr.addstr(
435
- 6, cols['PORT'], f"{
436
- 'Port':<{
437
- widths['PORT']}}", hdr_attr)
434
+ 6, cols['PORT'], f"{'Port':<{widths['PORT']}}", hdr_attr)
438
435
  self.stdscr.addstr(
439
- 6, cols['FW'], f"{
440
- 'Firmware':<{
441
- widths['FW']}}", hdr_attr)
436
+ 6, cols['FW'], f"{'Firmware':<{widths['FW']}}", hdr_attr)
442
437
  self.stdscr.addstr(
443
- 6, cols['UID'], f"{
444
- 'UID':<{
445
- widths['UID']}}", hdr_attr)
438
+ 6, cols['UID'], f"{'UID':<{widths['UID']}}", hdr_attr)
446
439
  self.stdscr.addstr(
447
- 6, cols['STATUS'], f"{
448
- 'Status':<{
449
- widths['STATUS']}}", hdr_attr)
440
+ 6, cols['STATUS'],
441
+ f"{'Status':<{widths['STATUS']}}", hdr_attr)
450
442
  self.stdscr.addstr(6, cols['ACTIVE'], "Active", hdr_attr)
451
443
  except curses.error:
452
444
  pass
@@ -490,21 +482,19 @@ class TUICore:
490
482
  try:
491
483
  self.stdscr.addstr(row, cols['SEL'], cursor, row_color)
492
484
  self.stdscr.addstr(
493
- row, cols['MODEL'], f"{
494
- model_str:<{
495
- widths['MODEL']}}", row_color)
485
+ row, cols['MODEL'],
486
+ f"{model_str:<{widths['MODEL']}}", row_color)
496
487
  self.stdscr.addstr(
497
- row, cols['PORT'], f"{
498
- port:<{
499
- widths['PORT']}}", row_color)
488
+ row, cols['PORT'],
489
+ f"{port:<{widths['PORT']}}", row_color)
500
490
 
501
491
  if is_busy:
502
492
  self.stdscr.addstr(
503
- row, cols['FW'], f"{'N/A':<{widths['FW']}}", row_color)
493
+ row, cols['FW'],
494
+ f"{'N/A':<{widths['FW']}}", row_color)
504
495
  self.stdscr.addstr(
505
- row, cols['UID'], f"{
506
- dev_uid:<{
507
- widths['UID']}}", curses.color_pair(
496
+ row, cols['UID'], f"{dev_uid:<{widths['UID']}}",
497
+ curses.color_pair(
508
498
  Config.COLOR_PAIRS['caution']) | curses.A_BOLD)
509
499
  else:
510
500
  try:
@@ -513,18 +503,15 @@ class TUICore:
513
503
  except (TypeError, ValueError):
514
504
  fw_str = "0x????????"
515
505
  self.stdscr.addstr(
516
- row, cols['FW'], f"{
517
- fw_str:<{
518
- widths['FW']}}", row_color)
506
+ row, cols['FW'],
507
+ f"{fw_str:<{widths['FW']}}", row_color)
519
508
  self.stdscr.addstr(
520
- row, cols['UID'], f"{
521
- dev_uid:<{
522
- widths['UID']}}", row_color)
509
+ row, cols['UID'],
510
+ f"{dev_uid:<{widths['UID']}}", row_color)
523
511
 
524
512
  self.stdscr.addstr(
525
- row, cols['STATUS'], f"{
526
- status:<{
527
- widths['STATUS']}}", status_color)
513
+ row, cols['STATUS'],
514
+ f"{status:<{widths['STATUS']}}", status_color)
528
515
 
529
516
  if is_active:
530
517
  self.stdscr.addstr(
@@ -616,8 +603,7 @@ class TUICore:
616
603
 
617
604
  self._draw_section(16, 2, "TUI")
618
605
  self.stdscr.addstr(
619
- 17, 4, f"{
620
- 'Refresh Interval':<22} {refresh_interval} s")
606
+ 17, 4, f"{'Refresh Interval':<22} {refresh_interval} s")
621
607
 
622
608
  except curses.error:
623
609
  pass
@@ -1145,8 +1131,7 @@ class TUICore:
1145
1131
  self.stdscr.addstr(
1146
1132
  row,
1147
1133
  cols['NAME'] + 2,
1148
- f"Fan{
1149
- i:<5}",
1134
+ f"Fan{i:<5}",
1150
1135
  fan_color)
1151
1136
  self.stdscr.addstr(
1152
1137
  row, cols['DUTY'] + 2, f"{duty:>5}%", fan_color)
@@ -1282,9 +1267,7 @@ class TUICore:
1282
1267
 
1283
1268
  try:
1284
1269
  self.stdscr.addstr(
1285
- y, x, f"{
1286
- label:<14} {val_str} {
1287
- unit:<3} ", color)
1270
+ y, x, f"{label:<14} {val_str} {unit:<3} ", color)
1288
1271
  self.stdscr.addstr(bar, color)
1289
1272
 
1290
1273
  if stat and stat[0] is not None:
@@ -118,8 +118,8 @@ class TUIApplication:
118
118
 
119
119
  if self.source_type == 'fastapi':
120
120
  if hasattr(args, 'api_port'):
121
- datasource_kwargs['base_url'] = f"http://127.0.0.1:{
122
- args.api_port}"
121
+ datasource_kwargs['base_url'] = (
122
+ f"http://127.0.0.1:{args.api_port}")
123
123
  else:
124
124
  datasource_kwargs['base_url'] = "http://127.0.0.1:8000"
125
125
  datasource_kwargs['timeout'] = 5.0
@@ -234,26 +234,22 @@ class TUIApplication:
234
234
  if self.datasource_manager.connect():
235
235
  uid = self.datasource_manager.get_selected_uid()
236
236
  self.tui_core.set_status(
237
- f"Connected via {
238
- self.source_type.upper()}")
237
+ f"Connected via {self.source_type.upper()}")
239
238
  logger.info(
240
- f"Connected to {
241
- self.source_type} datasource, selected: {uid}")
239
+ f"Connected to {self.source_type} datasource, "
240
+ f"selected: {uid}")
242
241
  else:
243
242
  snapshot = self.datasource_manager.snapshot()
244
243
  error_msg = snapshot.get(
245
- 'last_error', f"Failed to connect to {
246
- self.source_type}")
244
+ 'last_error', f"Failed to connect to {self.source_type}")
247
245
  self.tui_core.set_status(
248
246
  f"Connection failed: {error_msg}", 5.0)
249
247
  logger.error(
250
- f"Failed to connect to {
251
- self.source_type}: {error_msg}")
248
+ f"Failed to connect to {self.source_type}: {error_msg}")
252
249
  except Exception as e:
253
250
  self.tui_core.set_status(f"Connection error: {str(e)}", 5.0)
254
251
  logger.error(
255
- f"Exception during {
256
- self.source_type} connection: {e}")
252
+ f"Exception during {self.source_type} connection: {e}")
257
253
 
258
254
  def _connect_to_device(self, device: Dict[str, Any]):
259
255
  port = device.get('port')
@@ -280,8 +276,7 @@ class TUIApplication:
280
276
  if self.datasource_manager.select_device(uid):
281
277
  self.tui_core.set_status(f"Selected device {uid}")
282
278
  logger.info(
283
- f"Selected device {uid} via {
284
- self.source_type}")
279
+ f"Selected device {uid} via {self.source_type}")
285
280
  else:
286
281
  self.tui_core.set_status("Failed to select device", 3.0)
287
282
  logger.warning(f"Failed to select device {uid}")
@@ -147,8 +147,7 @@ def start_vu_server() -> subprocess.Popen | None:
147
147
  time.sleep(1)
148
148
  if check_vu_server(new_cfg["vu_server_url"], new_cfg["api_key"]):
149
149
  logger.info(
150
- f"VU server is now running at {
151
- new_cfg['vu_server_url']}")
150
+ f"VU server is now running at {new_cfg['vu_server_url']}")
152
151
  break
153
152
  else:
154
153
  logger.error("Failed to verify VU server after startup.")
@@ -159,8 +158,7 @@ def start_vu_server() -> subprocess.Popen | None:
159
158
  try:
160
159
  VU_SERVER_CONFIG.write_text(json.dumps(new_cfg, indent=2))
161
160
  logger.info(
162
- f"Updated {VU_SERVER_CONFIG} with {
163
- new_cfg['vu_server_url']}")
161
+ f"Updated {VU_SERVER_CONFIG} with {new_cfg['vu_server_url']}")
164
162
  except Exception as e:
165
163
  logger.warning(f"Failed to write {VU_SERVER_CONFIG}: {e}")
166
164