runtimepy 5.15.4__tar.gz → 5.15.6__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 (330) hide show
  1. {runtimepy-5.15.4/runtimepy.egg-info → runtimepy-5.15.6}/PKG-INFO +6 -6
  2. {runtimepy-5.15.4 → runtimepy-5.15.6}/README.md +2 -2
  3. {runtimepy-5.15.4 → runtimepy-5.15.6}/pyproject.toml +1 -1
  4. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/__init__.py +2 -2
  5. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/channel/environment/command/processor.py +11 -1
  6. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/css/bootstrap_extra.css +4 -0
  7. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/css/main.css +8 -0
  8. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/dummy_load.yaml +41 -21
  9. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/classes/WorkerInterface.js +1 -1
  10. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/sample.js +1 -1
  11. runtimepy-5.15.6/runtimepy/data/schemas/Button.yaml +17 -0
  12. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/schemas/ClientConnectionConfig.yaml +1 -0
  13. runtimepy-5.15.6/runtimepy/data/schemas/has_buttons.yaml +6 -0
  14. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/arbiter/base.py +12 -0
  15. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/arbiter/config/__init__.py +1 -0
  16. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/arbiter/factory/connection.py +3 -0
  17. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/app/env/tab/base.py +11 -0
  18. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/app/env/tab/html.py +10 -0
  19. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/app/env/widgets.py +11 -11
  20. runtimepy-5.15.6/runtimepy/net/server/markdown.py +101 -0
  21. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/websocket/__init__.py +1 -1
  22. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/requirements.txt +1 -1
  23. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/struct/__init__.py +2 -0
  24. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/task/basic/periodic.py +2 -0
  25. runtimepy-5.15.6/runtimepy/ui/button.py +76 -0
  26. {runtimepy-5.15.4 → runtimepy-5.15.6/runtimepy.egg-info}/PKG-INFO +6 -6
  27. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy.egg-info/SOURCES.txt +3 -0
  28. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy.egg-info/requires.txt +3 -3
  29. runtimepy-5.15.4/runtimepy/net/server/markdown.py +0 -71
  30. {runtimepy-5.15.4 → runtimepy-5.15.6}/LICENSE +0 -0
  31. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/__main__.py +0 -0
  32. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/app.py +0 -0
  33. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/channel/__init__.py +0 -0
  34. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/channel/environment/__init__.py +0 -0
  35. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/channel/environment/array.py +0 -0
  36. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/channel/environment/base.py +0 -0
  37. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/channel/environment/command/__init__.py +0 -0
  38. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/channel/environment/command/parser.py +0 -0
  39. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/channel/environment/command/result.py +0 -0
  40. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/channel/environment/create.py +0 -0
  41. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/channel/environment/file.py +0 -0
  42. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/channel/environment/sample.py +0 -0
  43. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/channel/environment/telemetry.py +0 -0
  44. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/channel/event/__init__.py +0 -0
  45. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/channel/event/header.py +0 -0
  46. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/channel/registry.py +0 -0
  47. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/codec/__init__.py +0 -0
  48. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/codec/protocol/__init__.py +0 -0
  49. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/codec/protocol/base.py +0 -0
  50. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/codec/protocol/json.py +0 -0
  51. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/codec/protocol/receiver.py +0 -0
  52. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/codec/system/__init__.py +0 -0
  53. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/commands/__init__.py +0 -0
  54. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/commands/all.py +0 -0
  55. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/commands/arbiter.py +0 -0
  56. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/commands/common.py +0 -0
  57. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/commands/mtu.py +0 -0
  58. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/commands/server.py +0 -0
  59. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/commands/task.py +0 -0
  60. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/commands/tftp.py +0 -0
  61. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/commands/tui.py +0 -0
  62. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/control/__init__.py +0 -0
  63. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/control/env/__init__.py +0 -0
  64. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/control/source.py +0 -0
  65. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/control/step.py +0 -0
  66. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/404.md +0 -0
  67. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/base.yaml +0 -0
  68. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/browser.yaml +0 -0
  69. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/css/font.css +0 -0
  70. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/factories.yaml +0 -0
  71. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/favicon.ico +0 -0
  72. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/DataConnection.js +0 -0
  73. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/JsonConnection.js +0 -0
  74. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/audio.js +0 -0
  75. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/classes/App.js +0 -0
  76. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/classes/ChannelTable.js +0 -0
  77. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/classes/DataConnection.js +0 -0
  78. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/classes/JsonConnection.js +0 -0
  79. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/classes/OverlayManager.js +0 -0
  80. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/classes/Plot.js +0 -0
  81. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/classes/PlotDrawer.js +0 -0
  82. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/classes/PlotManager.js +0 -0
  83. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/classes/PlotModalManager.js +0 -0
  84. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/classes/PointBuffer.js +0 -0
  85. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/classes/PointManager.js +0 -0
  86. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/classes/TabFilter.js +0 -0
  87. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/classes/TabInterface.js +0 -0
  88. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/classes/UnitSystem.js +0 -0
  89. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/classes/WindowHashManager.js +0 -0
  90. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/events.js +0 -0
  91. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/init.js +0 -0
  92. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/main.js +0 -0
  93. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/markdown_page.js +0 -0
  94. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/tab/env.js +0 -0
  95. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/tab/sound.js +0 -0
  96. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/third-party/webgl-debug.js +0 -0
  97. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/unused/pyodide.js +0 -0
  98. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/util.js +0 -0
  99. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/js/worker.js +0 -0
  100. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/md/Connection.md +0 -0
  101. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/md/PeriodicTask.md +0 -0
  102. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/md/RuntimeStruct.md +0 -0
  103. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/md/RuntimepyPeer.md +0 -0
  104. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/md/SinusoidTask.md +0 -0
  105. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/sample_telemetry.yaml +0 -0
  106. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/schemas/BitFields.yaml +0 -0
  107. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/schemas/Channel.yaml +0 -0
  108. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/schemas/ChannelCommand.yaml +0 -0
  109. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/schemas/ChannelRegistry.yaml +0 -0
  110. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/schemas/ConnectionArbiterConfig.yaml +0 -0
  111. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/schemas/EnumRegistry.yaml +0 -0
  112. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/schemas/FindFile.yaml +0 -0
  113. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/schemas/PeerProcessConfig.yaml +0 -0
  114. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/schemas/RuntimeEnum.yaml +0 -0
  115. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/schemas/ServerConnectionConfig.yaml +0 -0
  116. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/schemas/StructConfig.yaml +0 -0
  117. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/schemas/TaskConfig.yaml +0 -0
  118. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/schemas/TwoTupleArray.yaml +0 -0
  119. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/schemas/channel_controls.yaml +0 -0
  120. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/schemas/has_config.yaml +0 -0
  121. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/schemas/has_factory.yaml +0 -0
  122. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/schemas/has_markdown.yaml +0 -0
  123. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/schemas/has_name.yaml +0 -0
  124. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/schemas/has_request_flag.yaml +0 -0
  125. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/schemas/has_views.yaml +0 -0
  126. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/server.yaml +0 -0
  127. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/server_base.yaml +0 -0
  128. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/server_dev.yaml +0 -0
  129. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/css/bootstrap-icons.min.css +0 -0
  130. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/css/bootstrap.min.css +0 -0
  131. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/css/fonts/bootstrap-icons.woff +0 -0
  132. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/css/fonts/bootstrap-icons.woff2 +0 -0
  133. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/js/bootstrap.bundle.min.js +0 -0
  134. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/js/webglplot.umd.min.js +0 -0
  135. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/png/chip-circle-bootstrap/1024x1024.png +0 -0
  136. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/png/chip-circle-bootstrap/128x128.png +0 -0
  137. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/png/chip-circle-bootstrap/16x16.png +0 -0
  138. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/png/chip-circle-bootstrap/1920x1920.png +0 -0
  139. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/png/chip-circle-bootstrap/24x24.png +0 -0
  140. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/png/chip-circle-bootstrap/256x256.png +0 -0
  141. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/png/chip-circle-bootstrap/32x32.png +0 -0
  142. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/png/chip-circle-bootstrap/512x512.png +0 -0
  143. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/png/chip-circle-bootstrap/64x64.png +0 -0
  144. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/svg/chip-circle-bootstrap.svg +0 -0
  145. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/svg/outline-dark.svg +0 -0
  146. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/svg/outline-light.svg +0 -0
  147. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/woff2/CascadiaCode-Bold.woff2 +0 -0
  148. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/woff2/CascadiaCode-BoldItalic.woff2 +0 -0
  149. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/woff2/CascadiaCode-Italic.woff2 +0 -0
  150. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/woff2/CascadiaCode-Regular.woff2 +0 -0
  151. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/woff2/CascadiaMono-Bold.woff2 +0 -0
  152. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/woff2/CascadiaMono-BoldItalic.woff2 +0 -0
  153. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/woff2/CascadiaMono-Italic.woff2 +0 -0
  154. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/woff2/CascadiaMono-Regular.woff2 +0 -0
  155. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/static/woff2/README.md +0 -0
  156. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/data/tftp_server.yaml +0 -0
  157. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/dev_requirements.txt +0 -0
  158. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/entry.py +0 -0
  159. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/enum/__init__.py +0 -0
  160. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/enum/registry.py +0 -0
  161. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/enum/types.py +0 -0
  162. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/mapping.py +0 -0
  163. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/message/__init__.py +0 -0
  164. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/message/handlers.py +0 -0
  165. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/message/interface.py +0 -0
  166. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/message/types.py +0 -0
  167. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/metrics/__init__.py +0 -0
  168. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/metrics/channel.py +0 -0
  169. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/metrics/connection.py +0 -0
  170. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/metrics/task.py +0 -0
  171. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/mixins/__init__.py +0 -0
  172. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/mixins/async_command.py +0 -0
  173. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/mixins/enum.py +0 -0
  174. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/mixins/environment.py +0 -0
  175. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/mixins/finalize.py +0 -0
  176. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/mixins/logging.py +0 -0
  177. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/mixins/psutil.py +0 -0
  178. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/mixins/regex.py +0 -0
  179. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/mixins/trig.py +0 -0
  180. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/__init__.py +0 -0
  181. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/apps/__init__.py +0 -0
  182. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/arbiter/__init__.py +0 -0
  183. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/arbiter/config/codec.py +0 -0
  184. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/arbiter/config/util.py +0 -0
  185. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/arbiter/factory/__init__.py +0 -0
  186. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/arbiter/factory/task.py +0 -0
  187. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/arbiter/housekeeping/__init__.py +0 -0
  188. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/arbiter/imports/__init__.py +0 -0
  189. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/arbiter/imports/util.py +0 -0
  190. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/arbiter/info.py +0 -0
  191. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/arbiter/result.py +0 -0
  192. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/arbiter/struct/__init__.py +0 -0
  193. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/arbiter/task.py +0 -0
  194. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/arbiter/tcp/__init__.py +0 -0
  195. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/arbiter/tcp/json.py +0 -0
  196. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/arbiter/udp.py +0 -0
  197. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/arbiter/websocket.py +0 -0
  198. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/backoff.py +0 -0
  199. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/connection.py +0 -0
  200. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/factories/__init__.py +0 -0
  201. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/html/__init__.py +0 -0
  202. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/html/arbiter.py +0 -0
  203. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/html/bootstrap/__init__.py +0 -0
  204. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/html/bootstrap/elements.py +0 -0
  205. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/html/bootstrap/tabs.py +0 -0
  206. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/http/__init__.py +0 -0
  207. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/http/common.py +0 -0
  208. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/http/header.py +0 -0
  209. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/http/request_target.py +0 -0
  210. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/http/response.py +0 -0
  211. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/http/state.py +0 -0
  212. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/http/version.py +0 -0
  213. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/manager.py +0 -0
  214. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/mixin.py +0 -0
  215. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/mtu.py +0 -0
  216. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/__init__.py +0 -0
  217. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/app/__init__.py +0 -0
  218. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/app/base.py +0 -0
  219. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/app/create.py +0 -0
  220. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/app/elements.py +0 -0
  221. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/app/env/__init__.py +0 -0
  222. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/app/env/modal.py +0 -0
  223. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/app/env/settings.py +0 -0
  224. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/app/env/tab/__init__.py +0 -0
  225. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/app/env/tab/controls.py +0 -0
  226. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/app/env/tab/message.py +0 -0
  227. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/app/files.py +0 -0
  228. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/app/landing_page.py +0 -0
  229. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/app/placeholder.py +0 -0
  230. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/app/pyodide.py +0 -0
  231. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/app/sound.py +0 -0
  232. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/app/tab.py +0 -0
  233. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/html.py +0 -0
  234. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/json.py +0 -0
  235. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/mux.py +0 -0
  236. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/struct/__init__.py +0 -0
  237. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/server/websocket/state.py +0 -0
  238. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/ssl.py +0 -0
  239. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/stream/__init__.py +0 -0
  240. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/stream/base.py +0 -0
  241. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/stream/json/__init__.py +0 -0
  242. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/stream/string.py +0 -0
  243. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/tcp/__init__.py +0 -0
  244. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/tcp/connection.py +0 -0
  245. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/tcp/create.py +0 -0
  246. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/tcp/http/__init__.py +0 -0
  247. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/tcp/protocol.py +0 -0
  248. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/tcp/scpi/__init__.py +0 -0
  249. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/tcp/telnet/__init__.py +0 -0
  250. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/tcp/telnet/codes.py +0 -0
  251. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/tcp/telnet/np_05b.py +0 -0
  252. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/udp/__init__.py +0 -0
  253. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/udp/connection.py +0 -0
  254. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/udp/create.py +0 -0
  255. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/udp/protocol.py +0 -0
  256. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/udp/queue.py +0 -0
  257. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/udp/tftp/__init__.py +0 -0
  258. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/udp/tftp/base.py +0 -0
  259. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/udp/tftp/endpoint.py +0 -0
  260. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/udp/tftp/enums.py +0 -0
  261. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/udp/tftp/io.py +0 -0
  262. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/util.py +0 -0
  263. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/websocket/__init__.py +0 -0
  264. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/net/websocket/connection.py +0 -0
  265. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/noise/__init__.py +0 -0
  266. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/__init__.py +0 -0
  267. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/array/__init__.py +0 -0
  268. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/base.py +0 -0
  269. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/bool.py +0 -0
  270. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/byte_order.py +0 -0
  271. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/evaluation.py +0 -0
  272. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/field/__init__.py +0 -0
  273. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/field/fields.py +0 -0
  274. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/field/manager/__init__.py +0 -0
  275. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/field/manager/base.py +0 -0
  276. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/float.py +0 -0
  277. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/int.py +0 -0
  278. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/scaling.py +0 -0
  279. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/serializable/__init__.py +0 -0
  280. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/serializable/base.py +0 -0
  281. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/serializable/fixed.py +0 -0
  282. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/serializable/framer.py +0 -0
  283. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/serializable/prefixed.py +0 -0
  284. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/string.py +0 -0
  285. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/types/__init__.py +0 -0
  286. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/types/base.py +0 -0
  287. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/types/bool.py +0 -0
  288. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/types/bounds.py +0 -0
  289. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/types/float.py +0 -0
  290. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/primitives/types/int.py +0 -0
  291. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/py.typed +0 -0
  292. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/registry/__init__.py +0 -0
  293. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/registry/bool.py +0 -0
  294. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/registry/item.py +0 -0
  295. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/registry/name.py +0 -0
  296. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/sample/__init__.py +0 -0
  297. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/sample/peer.py +0 -0
  298. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/sample/program.py +0 -0
  299. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/schemas.py +0 -0
  300. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/subprocess/__init__.py +0 -0
  301. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/subprocess/interface.py +0 -0
  302. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/subprocess/peer.py +0 -0
  303. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/subprocess/program.py +0 -0
  304. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/subprocess/protocol.py +0 -0
  305. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/task/__init__.py +0 -0
  306. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/task/asynchronous.py +0 -0
  307. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/task/basic/__init__.py +0 -0
  308. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/task/basic/manager.py +0 -0
  309. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/task/sample.py +0 -0
  310. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/task/trig/__init__.py +0 -0
  311. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/telemetry/__init__.py +0 -0
  312. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/telemetry/sample.py +0 -0
  313. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/tui/__init__.py +0 -0
  314. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/tui/channels/__init__.py +0 -0
  315. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/tui/cursor.py +0 -0
  316. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/tui/mixin.py +0 -0
  317. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/tui/mock.py +0 -0
  318. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/tui/task.py +0 -0
  319. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/ui/__init__.py +0 -0
  320. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/ui/controls.py +0 -0
  321. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy/util.py +0 -0
  322. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy.egg-info/dependency_links.txt +0 -0
  323. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy.egg-info/entry_points.txt +0 -0
  324. {runtimepy-5.15.4 → runtimepy-5.15.6}/runtimepy.egg-info/top_level.txt +0 -0
  325. {runtimepy-5.15.4 → runtimepy-5.15.6}/setup.cfg +0 -0
  326. {runtimepy-5.15.4 → runtimepy-5.15.6}/setup.py +0 -0
  327. {runtimepy-5.15.4 → runtimepy-5.15.6}/tests/test_entry.py +0 -0
  328. {runtimepy-5.15.4 → runtimepy-5.15.6}/tests/test_mapping.py +0 -0
  329. {runtimepy-5.15.4 → runtimepy-5.15.6}/tests/test_resources.py +0 -0
  330. {runtimepy-5.15.4 → runtimepy-5.15.6}/tests/test_util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: runtimepy
3
- Version: 5.15.4
3
+ Version: 5.15.6
4
4
  Summary: A framework for implementing Python services.
5
5
  Home-page: https://github.com/libre-embedded/runtimepy
6
6
  Author: Libre Embedded
@@ -17,11 +17,11 @@ Classifier: Development Status :: 5 - Production/Stable
17
17
  Requires-Python: >=3.12
18
18
  Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
- Requires-Dist: vcorelib>=3.6.3
21
- Requires-Dist: websockets
22
- Requires-Dist: svgen>=0.8.0
23
20
  Requires-Dist: aiofiles
21
+ Requires-Dist: svgen>=0.8.0
24
22
  Requires-Dist: psutil
23
+ Requires-Dist: vcorelib>=3.6.4
24
+ Requires-Dist: websockets
25
25
  Provides-Extra: test
26
26
  Requires-Dist: pylint; extra == "test"
27
27
  Requires-Dist: flake8; extra == "test"
@@ -51,11 +51,11 @@ Dynamic: requires-python
51
51
  =====================================
52
52
  generator=datazen
53
53
  version=3.2.3
54
- hash=99eea1986d2105483ebb2fe566128f5f
54
+ hash=0f8ffdbd46445346cb834d066f58e765
55
55
  =====================================
56
56
  -->
57
57
 
58
- # runtimepy ([5.15.4](https://pypi.org/project/runtimepy/))
58
+ # runtimepy ([5.15.6](https://pypi.org/project/runtimepy/))
59
59
 
60
60
  [![python](https://img.shields.io/pypi/pyversions/runtimepy.svg)](https://pypi.org/project/runtimepy/)
61
61
  ![Build Status](https://github.com/libre-embedded/runtimepy/workflows/Python%20Package/badge.svg)
@@ -2,11 +2,11 @@
2
2
  =====================================
3
3
  generator=datazen
4
4
  version=3.2.3
5
- hash=99eea1986d2105483ebb2fe566128f5f
5
+ hash=0f8ffdbd46445346cb834d066f58e765
6
6
  =====================================
7
7
  -->
8
8
 
9
- # runtimepy ([5.15.4](https://pypi.org/project/runtimepy/))
9
+ # runtimepy ([5.15.6](https://pypi.org/project/runtimepy/))
10
10
 
11
11
  [![python](https://img.shields.io/pypi/pyversions/runtimepy.svg)](https://pypi.org/project/runtimepy/)
12
12
  ![Build Status](https://github.com/libre-embedded/runtimepy/workflows/Python%20Package/badge.svg)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta:__legacy__"
4
4
 
5
5
  [project]
6
6
  name = "runtimepy"
7
- version = "5.15.4"
7
+ version = "5.15.6"
8
8
  description = "A framework for implementing Python services."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -1,7 +1,7 @@
1
1
  # =====================================
2
2
  # generator=datazen
3
3
  # version=3.2.3
4
- # hash=b0f0463a508c9a1312a071f5c0b06f3b
4
+ # hash=08c1dda8bd5fefe13af6a8eb49063498
5
5
  # =====================================
6
6
 
7
7
  """
@@ -10,7 +10,7 @@ Useful defaults and other package metadata.
10
10
 
11
11
  DESCRIPTION = "A framework for implementing Python services."
12
12
  PKG_NAME = "runtimepy"
13
- VERSION = "5.15.4"
13
+ VERSION = "5.15.6"
14
14
 
15
15
  # runtimepy-specific content.
16
16
  METRICS_NAME = "metrics"
@@ -20,6 +20,7 @@ from runtimepy.channel.environment.command.result import SUCCESS, CommandResult
20
20
  from runtimepy.mixins.environment import ChannelEnvironmentMixin
21
21
  from runtimepy.primitives.bool import Bool
22
22
  from runtimepy.primitives.field import BitField
23
+ from runtimepy.ui.button import ActionButton
23
24
 
24
25
  CommandHook = Callable[[Namespace, Optional[FieldOrChannel]], None]
25
26
 
@@ -33,7 +34,11 @@ class ChannelCommandProcessor(ChannelEnvironmentMixin):
33
34
  """A command processing interface for channel environments."""
34
35
 
35
36
  def __init__(
36
- self, env: ChannelEnvironment, logger: LoggerType, **kwargs
37
+ self,
38
+ env: ChannelEnvironment,
39
+ logger: LoggerType,
40
+ buttons: list[ActionButton] = None,
41
+ **kwargs,
37
42
  ) -> None:
38
43
  """Initialize this instance."""
39
44
 
@@ -49,6 +54,11 @@ class ChannelCommandProcessor(ChannelEnvironmentMixin):
49
54
 
50
55
  self.parser.initialize()
51
56
 
57
+ # Action buttons.
58
+ if buttons is None:
59
+ buttons = []
60
+ self.buttons: list[ActionButton] = buttons
61
+
52
62
  def register_custom_commands(
53
63
  self, *custom_commands: CustomCommand
54
64
  ) -> None:
@@ -110,6 +110,10 @@ select:hover {
110
110
  background-image: linear-gradient(to bottom, var(--bs-tertiary-bg), rgba(var(--bs-tertiary-bg-rgb), 0), var(--bs-tertiary-bg));
111
111
  }
112
112
 
113
+ .bg-gradient-tertiary-left-right {
114
+ background-image: linear-gradient(to right, var(--bs-tertiary-bg), rgba(var(--bs-tertiary-bg-rgb), 0), var(--bs-tertiary-bg));
115
+ }
116
+
113
117
  .border-start-info-subtle {
114
118
  border-left: var(--bs-border-width) var(--bs-border-style) var(--bs-info-border-subtle);
115
119
  }
@@ -74,3 +74,11 @@ body > :first-child {
74
74
  .overscroll-behavior-none {
75
75
  overscroll-behavior: none;
76
76
  }
77
+
78
+ .channel-views-min-width {
79
+ min-width: 5.5em;
80
+ }
81
+
82
+ .channel-filter-min-width {
83
+ min-width: 5.5em;
84
+ }
@@ -1,4 +1,42 @@
1
1
  ---
2
+ # UDP JSON clients.
3
+ clients:
4
+ - factory: udp_json
5
+ name: udp_json_client
6
+ defer: true
7
+ kwargs:
8
+ remote_addr: [localhost, "$udp_json"]
9
+ views:
10
+ - [metrics, metrics]
11
+ - [transmit, tx]
12
+ - [receive, rx]
13
+ buttons: &buttons
14
+ - icon: tux
15
+ key: test
16
+ payload: {}
17
+ - icon: tux
18
+ key: test
19
+ text: asdf
20
+ payload: {}
21
+ - icon: tux
22
+ key: test
23
+ payload: {}
24
+ outline: false
25
+ - icon: tux
26
+ key: test
27
+ text: asdf
28
+ payload: {}
29
+ outline: false
30
+ markdown: |
31
+ # `udp_json_client`
32
+
33
+ Connects to `udp_json_server`.
34
+
35
+ - factory: udp_json
36
+ name: udp_json_server
37
+ kwargs:
38
+ local_addr: [localhost, "$udp_json"]
39
+
2
40
  # Add some sample tasks.
3
41
  tasks:
4
42
  # Chaos.
@@ -9,6 +47,7 @@ tasks:
9
47
  a: 1
10
48
  b: 2
11
49
  c: 3
50
+ buttons: *buttons
12
51
  views:
13
52
  - [zero, "\\.0\\."]
14
53
  - [one, "\\.1\\."]
@@ -49,27 +88,6 @@ tasks:
49
88
  # Drive interactions with runtime entities that won't otherwise be polled.
50
89
  - {name: app, factory: SampleApp, period_s: 0.25}
51
90
 
52
- # UDP JSON clients.
53
- clients:
54
- - factory: udp_json
55
- name: udp_json_client
56
- defer: true
57
- kwargs:
58
- remote_addr: [localhost, "$udp_json"]
59
- views:
60
- - [metrics, metrics]
61
- - [transmit, tx]
62
- - [receive, rx]
63
- markdown: |
64
- # `udp_json_client`
65
-
66
- Connects to `udp_json_server`.
67
-
68
- - factory: udp_json
69
- name: udp_json_server
70
- kwargs:
71
- local_addr: [localhost, "$udp_json"]
72
-
73
91
  # Add some sample structs.
74
92
  structs:
75
93
  - name: example.struct1
@@ -80,6 +98,8 @@ structs:
80
98
  b: 2
81
99
  c: 3
82
100
 
101
+ buttons: *buttons
102
+
83
103
  markdown: |
84
104
  # Docs for `example.struct1`
85
105
 
@@ -10,7 +10,7 @@ class WorkerInterface {
10
10
 
11
11
  command(data) { this.send({kind : "command", value : data}); }
12
12
 
13
- bus(data) { this.worker.postMessage({bus : data}); }
13
+ bus(key, data) { this.worker.postMessage({key : key, bus : data}); }
14
14
 
15
15
  toWorker(data, param) { return this.send({"worker" : data}, param); }
16
16
  }
@@ -1,2 +1,2 @@
1
1
  console.log(`sample.js included (${tab.name})`);
2
- // tab.worker.bus({a: 1, b: 2, c: 3});
2
+ // tab.worker.bus("test", {a: 1, b: 2, c: 3});
@@ -0,0 +1,17 @@
1
+ ---
2
+ type: object
3
+ additionalProperties: false
4
+ required: [key, payload]
5
+ properties:
6
+ key:
7
+ type: string
8
+ payload:
9
+ type: object
10
+ text:
11
+ type: string
12
+ icon:
13
+ type: string
14
+ variant:
15
+ type: string
16
+ outline:
17
+ type: boolean
@@ -4,6 +4,7 @@ includes:
4
4
  - has_name.yaml
5
5
  - has_markdown.yaml
6
6
  - has_views.yaml
7
+ - has_buttons.yaml
7
8
 
8
9
  properties:
9
10
  defer:
@@ -0,0 +1,6 @@
1
+ ---
2
+ properties:
3
+ buttons:
4
+ type: array
5
+ items:
6
+ $ref: package://runtimepy/schemas/Button.yaml
@@ -47,6 +47,7 @@ from runtimepy.net.manager import ConnectionManager as _ConnectionManager
47
47
  from runtimepy.net.server import RuntimepyServerConnection
48
48
  from runtimepy.subprocess.peer import RuntimepyPeer as _RuntimepyPeer
49
49
  from runtimepy.tui.mixin import CursesWindow, TuiMixin
50
+ from runtimepy.ui.button import ActionButton
50
51
 
51
52
  ServerTask = _Awaitable[None]
52
53
  RuntimeProcessTask = tuple[
@@ -148,6 +149,7 @@ class BaseConnectionArbiter(_NamespaceMixin, _LoggerMixin, TuiMixin):
148
149
 
149
150
  self._commands: list[tuple[str, str]] = []
150
151
  self._views: dict[str, dict[str, str]] = {}
152
+ self._buttons: dict[str, list[ActionButton]] = {}
151
153
 
152
154
  self._init()
153
155
 
@@ -157,9 +159,16 @@ class BaseConnectionArbiter(_NamespaceMixin, _LoggerMixin, TuiMixin):
157
159
  def _register_connection(self, connection: _Connection, name: str) -> None:
158
160
  """Perform connection registration."""
159
161
 
162
+ # Handle views.
160
163
  if name in self._views:
161
164
  connection.env.views.update(self._views[name])
162
165
  del self._views[name]
166
+
167
+ # Handle buttons.
168
+ if name in self._buttons:
169
+ connection.command.buttons.extend(self._buttons[name])
170
+ del self._buttons[name]
171
+
163
172
  self._connections[name] = connection
164
173
  self.manager.queue.put_nowait(connection)
165
174
  connection.logger.info("Registered as '%s'.", name)
@@ -170,6 +179,7 @@ class BaseConnectionArbiter(_NamespaceMixin, _LoggerMixin, TuiMixin):
170
179
  *names: str,
171
180
  delim: str = None,
172
181
  views: dict[str, str] = None,
182
+ buttons: list[ActionButton] = None,
173
183
  ) -> bool:
174
184
  """Attempt to register a connection object."""
175
185
 
@@ -180,6 +190,8 @@ class BaseConnectionArbiter(_NamespaceMixin, _LoggerMixin, TuiMixin):
180
190
 
181
191
  if views:
182
192
  self._views[name] = views
193
+ if buttons:
194
+ self._buttons[name] = buttons
183
195
 
184
196
  if (
185
197
  name not in self._connections
@@ -180,6 +180,7 @@ class ConfigConnectionArbiter(_ImportConnectionArbiter):
180
180
  **fix_kwargs(kwargs),
181
181
  views=client.get("views"),
182
182
  markdown=client.get("markdown"),
183
+ buttons=client.get("buttons", []),
183
184
  ), f"Couldn't register client '{name}' ({factory})!"
184
185
 
185
186
  # Register servers.
@@ -16,6 +16,7 @@ from runtimepy.net.arbiter.base import (
16
16
  from runtimepy.net.arbiter.base import ServerTask as _ServerTask
17
17
  from runtimepy.net.connection import Connection as _Connection
18
18
  from runtimepy.net.manager import ConnectionManager as _ConnectionManager
19
+ from runtimepy.ui.button import ActionButton
19
20
 
20
21
 
21
22
  class ConnectionFactory:
@@ -90,6 +91,7 @@ class FactoryConnectionArbiter(_BaseConnectionArbiter):
90
91
  factory_inst = self._conn_factories[factory]
91
92
 
92
93
  views = kwargs.pop("views", {})
94
+ buttons = ActionButton.from_top_level(kwargs.pop("buttons", []))
93
95
 
94
96
  conn = factory_inst.client(name, *args, **kwargs)
95
97
  if not defer:
@@ -100,6 +102,7 @@ class FactoryConnectionArbiter(_BaseConnectionArbiter):
100
102
  *self._conn_names[factory_inst],
101
103
  name,
102
104
  views=views,
105
+ buttons=buttons,
103
106
  )
104
107
 
105
108
  return result
@@ -2,6 +2,9 @@
2
2
  A module implementing a channel-environment tab HTML interface.
3
3
  """
4
4
 
5
+ # built-in
6
+ from io import StringIO
7
+
5
8
  # third-party
6
9
  from vcorelib.io.markdown import MarkdownMixin
7
10
  from vcorelib.logging import LoggerMixin
@@ -39,3 +42,11 @@ class ChannelEnvironmentTabBase(Tab, LoggerMixin, MarkdownMixin):
39
42
  # Logging.
40
43
  LoggerMixin.__init__(self, logger=self.command.logger)
41
44
  self.log_limiter = RateLimiter.from_s(1.0)
45
+
46
+ def _action_markdown(self) -> str:
47
+ """Get action-button markdown."""
48
+
49
+ with StringIO() as stream:
50
+ for button in self.command.buttons:
51
+ button.element().encode(stream)
52
+ return stream.getvalue()
@@ -289,6 +289,16 @@ class ChannelEnvironmentTabHtml(ChannelEnvironmentTabControls):
289
289
  )
290
290
  logs.booleans.add("readonly")
291
291
 
292
+ if self.command.buttons:
293
+ centered_markdown(
294
+ vert_container,
295
+ self._action_markdown(),
296
+ "border-start",
297
+ "border-bottom",
298
+ "border-end",
299
+ "bg-gradient-tertiary-left-right",
300
+ )
301
+
292
302
  self.channel_table(vert_container)
293
303
 
294
304
  centered_markdown(
@@ -84,15 +84,16 @@ def views_dropdown(parent: Element, command: ChannelCommandProcessor) -> None:
84
84
  """Dropdown menu for channel environment views."""
85
85
 
86
86
  select = select_element(
87
- parent=div(tag="th", parent=parent, class_str="p-0"),
87
+ parent=div(
88
+ tag="th", parent=parent, class_str="p-0 channel-views-min-width"
89
+ ),
88
90
  id="filter-view",
89
91
  title="Canonical channel filters.",
90
92
  ).add_class("border-end-0", "w-100")
91
93
  div(tag="option", value="", text="-", parent=select)
94
+ div(tag="option", value="^$", text="hide", parent=select)
92
95
  for text, value in command.env.views.items():
93
96
  div(tag="option", value=value, text=text, parent=select)
94
- if not command.env.views:
95
- select.booleans.add("disabled")
96
97
 
97
98
 
98
99
  def channel_table_header(
@@ -120,7 +121,11 @@ def channel_table_header(
120
121
  ).add_class(*TABLE_BUTTON_CLASSES)
121
122
 
122
123
  _, label, box = input_box(
123
- div(tag="th", parent=ctl_row, class_str="p-0 border-end-0"),
124
+ div(
125
+ tag="th",
126
+ parent=ctl_row,
127
+ class_str="p-0 border-end-0 channel-filter-min-width",
128
+ ),
124
129
  description="Channel name filter.",
125
130
  pattern=".* ! @ $",
126
131
  label="filter",
@@ -137,7 +142,7 @@ def channel_table_header(
137
142
  parent=div(tag="th", parent=ctl_row, colspan="2", class_str="p-0")
138
143
  )
139
144
 
140
- # Add a selection menu for custom commands. (need a data source for this)
145
+ # Add a selection menu for custom commands.
141
146
  select = select_element(
142
147
  parent=cell, id="custom-commands", title="Custom command selector."
143
148
  )
@@ -157,12 +162,7 @@ def channel_table_header(
157
162
  tooltip="Send selected command (left dropdown).",
158
163
  ).add_class(*TABLE_BUTTON_CLASSES)
159
164
  else:
160
- div(
161
- tag="option",
162
- parent=select,
163
- value="noop",
164
- text="no custom commands",
165
- )
165
+ div(tag="option", parent=select, value="noop", text="-")
166
166
  select.booleans.add("disabled")
167
167
 
168
168
  # Button for 'reset all defaults' if this tab has more than one channel
@@ -0,0 +1,101 @@
1
+ """
2
+ A module implementing web server markdown interfaces.
3
+ """
4
+
5
+ # built-in
6
+ from io import StringIO
7
+ import mimetypes
8
+ from pathlib import Path
9
+ from typing import Iterable, cast
10
+
11
+ # third-party
12
+ from svgen.element.html import div
13
+ from vcorelib.io.file_writer import IndentedFileWriter
14
+ from vcorelib.math.time import byte_count_str
15
+ from vcorelib.paths import rel
16
+ from vcorelib.paths import stats as _stats
17
+
18
+ LOGO_MARKDOWN = "[![logo](/static/png/chip-circle-bootstrap/128x128.png)](/)"
19
+ DIR_FILE = "dir.html"
20
+
21
+
22
+ def file_preview(path: Path, link: Path) -> str:
23
+ """Get possible preview text for a file."""
24
+
25
+ preview = ""
26
+
27
+ if path.is_file():
28
+ mime, _ = mimetypes.guess_type(path, strict=False)
29
+ if mime and mime.startswith("image"):
30
+ preview = div(tag="img", src=f"/{link}", alt=str(link)).encode_str(
31
+ newlines=False
32
+ )
33
+
34
+ return preview
35
+
36
+
37
+ def write_markdown_dir(
38
+ writer: IndentedFileWriter, path: Path, base: Path
39
+ ) -> None:
40
+ """Write markdown contents for a single directory."""
41
+
42
+ curr_dir = rel(path, base=base)
43
+
44
+ line = f"### `{base.name}/{curr_dir}`"
45
+
46
+ # Link to go up a directory.
47
+ if curr_dir != Path():
48
+ line += f" ([..](/{curr_dir.parent}/{DIR_FILE}))"
49
+
50
+ writer.write(line)
51
+ writer.empty()
52
+
53
+ writer.write("| name | size | preview |")
54
+ writer.write("|------|------|---------|")
55
+
56
+ for item in sorted(path.iterdir()):
57
+ curr = rel(item, base=base)
58
+
59
+ name = f"`{curr.name}`"
60
+ if item.is_dir():
61
+ name = f"**{name}**"
62
+
63
+ stats = _stats(item)
64
+ assert stats
65
+ size_str = byte_count_str(stats.st_size) if item.is_file() else ""
66
+
67
+ writer.write(
68
+ f"| [{name}](/{curr}) | {size_str} | {file_preview(item, curr)} |"
69
+ )
70
+
71
+ writer.empty()
72
+
73
+
74
+ def markdown_for_dir(
75
+ paths_bases: Iterable[tuple[Path, Path]],
76
+ extra_links: dict[str, Iterable[str]] = None,
77
+ ) -> str:
78
+ """Get markdown data for a directory."""
79
+
80
+ with IndentedFileWriter.string() as writer:
81
+ writer.write(f"# Directory {LOGO_MARKDOWN} Viewer")
82
+ with writer.padding():
83
+ writer.write("---")
84
+
85
+ if extra_links:
86
+ for category, apps in extra_links.items():
87
+ if apps:
88
+ writer.write(f"## {category}")
89
+ with writer.padding():
90
+ for app in apps:
91
+ writer.write(f"* [{app}]({app})")
92
+
93
+ writer.write("## directories")
94
+ writer.empty()
95
+
96
+ for path, base in paths_bases:
97
+ write_markdown_dir(writer, path, base)
98
+
99
+ result: str = cast(StringIO, writer.stream).getvalue()
100
+
101
+ return result
@@ -96,7 +96,7 @@ class RuntimepyWebsocketConnection(WebsocketJsonMessageConnection):
96
96
 
97
97
  # Handle bus messages.
98
98
  if "bus" in inbox:
99
- await BUS.send_ro("ui", inbox["bus"])
99
+ await BUS.send_ro(inbox["key"], inbox["bus"])
100
100
  return
101
101
 
102
102
  # Handle frame messages.
@@ -1,5 +1,5 @@
1
1
  aiofiles
2
- vcorelib>=3.6.3
2
+ vcorelib>=3.6.4
3
3
  svgen>=0.8.0
4
4
  websockets
5
5
  psutil
@@ -21,6 +21,7 @@ from runtimepy.channel.environment.command.processor import (
21
21
  from runtimepy.mixins.async_command import AsyncCommandProcessingMixin
22
22
  from runtimepy.mixins.environment import ChannelEnvironmentMixin
23
23
  from runtimepy.mixins.logging import LoggerMixinLevelControl
24
+ from runtimepy.ui.button import ActionButton
24
25
 
25
26
 
26
27
  class RuntimeStructBase(
@@ -50,6 +51,7 @@ class RuntimeStructBase(
50
51
  self.setup_level_channel(self.env)
51
52
  self.command = ChannelCommandProcessor(self.env, self.logger)
52
53
  self.config = config
54
+ self.command.buttons.extend(ActionButton.from_top_level(self.config))
53
55
 
54
56
  async def poll(args: Namespace, __: Optional[FieldOrChannel]) -> None:
55
57
  """Handle a test command."""
@@ -33,6 +33,7 @@ from runtimepy.primitives import Bool as _Bool
33
33
  from runtimepy.primitives import Double as _Double
34
34
  from runtimepy.primitives import Float as _Float
35
35
  from runtimepy.primitives.evaluation import EvalResult as _EvalResult
36
+ from runtimepy.ui.button import ActionButton
36
37
  from runtimepy.ui.controls import Controlslike
37
38
 
38
39
 
@@ -75,6 +76,7 @@ class PeriodicTask(
75
76
  self.env.views.update(self.config.get("views", {})) # type: ignore
76
77
  self.setup_level_channel(self.env)
77
78
  self.command = ChannelCommandProcessor(self.env, self.logger)
79
+ self.command.buttons.extend(ActionButton.from_top_level(self.config))
78
80
  self.register_task_metrics(self.metrics)
79
81
 
80
82
  # State.