runtimepy 5.15.3__tar.gz → 5.15.5__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 (329) hide show
  1. {runtimepy-5.15.3/runtimepy.egg-info → runtimepy-5.15.5}/PKG-INFO +7 -7
  2. {runtimepy-5.15.3 → runtimepy-5.15.5}/README.md +2 -2
  3. {runtimepy-5.15.3 → runtimepy-5.15.5}/pyproject.toml +1 -1
  4. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/__init__.py +2 -2
  5. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/channel/environment/base.py +5 -0
  6. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/channel/environment/command/processor.py +11 -1
  7. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/channel/environment/file.py +4 -0
  8. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/css/bootstrap_extra.css +4 -0
  9. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/css/main.css +8 -0
  10. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/dummy_load.yaml +47 -17
  11. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/classes/ChannelTable.js +4 -0
  12. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/classes/TabInterface.js +13 -0
  13. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/classes/WorkerInterface.js +1 -1
  14. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/init.js +4 -2
  15. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/sample.js +1 -1
  16. runtimepy-5.15.5/runtimepy/data/schemas/Button.yaml +17 -0
  17. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/schemas/ClientConnectionConfig.yaml +2 -0
  18. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/schemas/ConnectionArbiterConfig.yaml +1 -8
  19. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/schemas/PeerProcessConfig.yaml +1 -0
  20. runtimepy-5.15.5/runtimepy/data/schemas/TwoTupleArray.yaml +9 -0
  21. runtimepy-5.15.5/runtimepy/data/schemas/has_buttons.yaml +6 -0
  22. runtimepy-5.15.5/runtimepy/data/schemas/has_views.yaml +4 -0
  23. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/arbiter/base.py +20 -0
  24. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/arbiter/config/__init__.py +3 -1
  25. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/arbiter/factory/connection.py +9 -1
  26. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/app/env/tab/base.py +11 -0
  27. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/app/env/tab/html.py +10 -0
  28. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/app/env/widgets.py +25 -9
  29. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/websocket/__init__.py +1 -1
  30. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/requirements.txt +1 -1
  31. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/struct/__init__.py +3 -0
  32. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/task/basic/periodic.py +3 -0
  33. runtimepy-5.15.5/runtimepy/ui/button.py +76 -0
  34. {runtimepy-5.15.3 → runtimepy-5.15.5/runtimepy.egg-info}/PKG-INFO +7 -7
  35. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy.egg-info/SOURCES.txt +5 -0
  36. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy.egg-info/requires.txt +4 -4
  37. {runtimepy-5.15.3 → runtimepy-5.15.5}/LICENSE +0 -0
  38. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/__main__.py +0 -0
  39. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/app.py +0 -0
  40. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/channel/__init__.py +0 -0
  41. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/channel/environment/__init__.py +0 -0
  42. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/channel/environment/array.py +0 -0
  43. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/channel/environment/command/__init__.py +0 -0
  44. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/channel/environment/command/parser.py +0 -0
  45. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/channel/environment/command/result.py +0 -0
  46. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/channel/environment/create.py +0 -0
  47. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/channel/environment/sample.py +0 -0
  48. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/channel/environment/telemetry.py +0 -0
  49. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/channel/event/__init__.py +0 -0
  50. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/channel/event/header.py +0 -0
  51. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/channel/registry.py +0 -0
  52. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/codec/__init__.py +0 -0
  53. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/codec/protocol/__init__.py +0 -0
  54. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/codec/protocol/base.py +0 -0
  55. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/codec/protocol/json.py +0 -0
  56. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/codec/protocol/receiver.py +0 -0
  57. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/codec/system/__init__.py +0 -0
  58. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/commands/__init__.py +0 -0
  59. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/commands/all.py +0 -0
  60. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/commands/arbiter.py +0 -0
  61. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/commands/common.py +0 -0
  62. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/commands/mtu.py +0 -0
  63. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/commands/server.py +0 -0
  64. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/commands/task.py +0 -0
  65. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/commands/tftp.py +0 -0
  66. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/commands/tui.py +0 -0
  67. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/control/__init__.py +0 -0
  68. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/control/env/__init__.py +0 -0
  69. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/control/source.py +0 -0
  70. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/control/step.py +0 -0
  71. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/404.md +0 -0
  72. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/base.yaml +0 -0
  73. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/browser.yaml +0 -0
  74. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/css/font.css +0 -0
  75. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/factories.yaml +0 -0
  76. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/favicon.ico +0 -0
  77. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/DataConnection.js +0 -0
  78. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/JsonConnection.js +0 -0
  79. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/audio.js +0 -0
  80. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/classes/App.js +0 -0
  81. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/classes/DataConnection.js +0 -0
  82. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/classes/JsonConnection.js +0 -0
  83. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/classes/OverlayManager.js +0 -0
  84. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/classes/Plot.js +0 -0
  85. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/classes/PlotDrawer.js +0 -0
  86. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/classes/PlotManager.js +0 -0
  87. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/classes/PlotModalManager.js +0 -0
  88. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/classes/PointBuffer.js +0 -0
  89. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/classes/PointManager.js +0 -0
  90. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/classes/TabFilter.js +0 -0
  91. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/classes/UnitSystem.js +0 -0
  92. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/classes/WindowHashManager.js +0 -0
  93. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/events.js +0 -0
  94. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/main.js +0 -0
  95. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/markdown_page.js +0 -0
  96. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/tab/env.js +0 -0
  97. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/tab/sound.js +0 -0
  98. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/third-party/webgl-debug.js +0 -0
  99. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/unused/pyodide.js +0 -0
  100. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/util.js +0 -0
  101. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/js/worker.js +0 -0
  102. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/md/Connection.md +0 -0
  103. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/md/PeriodicTask.md +0 -0
  104. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/md/RuntimeStruct.md +0 -0
  105. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/md/RuntimepyPeer.md +0 -0
  106. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/md/SinusoidTask.md +0 -0
  107. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/sample_telemetry.yaml +0 -0
  108. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/schemas/BitFields.yaml +0 -0
  109. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/schemas/Channel.yaml +0 -0
  110. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/schemas/ChannelCommand.yaml +0 -0
  111. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/schemas/ChannelRegistry.yaml +0 -0
  112. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/schemas/EnumRegistry.yaml +0 -0
  113. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/schemas/FindFile.yaml +0 -0
  114. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/schemas/RuntimeEnum.yaml +0 -0
  115. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/schemas/ServerConnectionConfig.yaml +0 -0
  116. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/schemas/StructConfig.yaml +0 -0
  117. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/schemas/TaskConfig.yaml +0 -0
  118. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/schemas/channel_controls.yaml +0 -0
  119. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/schemas/has_config.yaml +0 -0
  120. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/schemas/has_factory.yaml +0 -0
  121. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/schemas/has_markdown.yaml +0 -0
  122. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/schemas/has_name.yaml +0 -0
  123. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/schemas/has_request_flag.yaml +0 -0
  124. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/server.yaml +0 -0
  125. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/server_base.yaml +0 -0
  126. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/server_dev.yaml +0 -0
  127. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/css/bootstrap-icons.min.css +0 -0
  128. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/css/bootstrap.min.css +0 -0
  129. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/css/fonts/bootstrap-icons.woff +0 -0
  130. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/css/fonts/bootstrap-icons.woff2 +0 -0
  131. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/js/bootstrap.bundle.min.js +0 -0
  132. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/js/webglplot.umd.min.js +0 -0
  133. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/png/chip-circle-bootstrap/1024x1024.png +0 -0
  134. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/png/chip-circle-bootstrap/128x128.png +0 -0
  135. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/png/chip-circle-bootstrap/16x16.png +0 -0
  136. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/png/chip-circle-bootstrap/1920x1920.png +0 -0
  137. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/png/chip-circle-bootstrap/24x24.png +0 -0
  138. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/png/chip-circle-bootstrap/256x256.png +0 -0
  139. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/png/chip-circle-bootstrap/32x32.png +0 -0
  140. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/png/chip-circle-bootstrap/512x512.png +0 -0
  141. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/png/chip-circle-bootstrap/64x64.png +0 -0
  142. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/svg/chip-circle-bootstrap.svg +0 -0
  143. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/svg/outline-dark.svg +0 -0
  144. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/svg/outline-light.svg +0 -0
  145. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/woff2/CascadiaCode-Bold.woff2 +0 -0
  146. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/woff2/CascadiaCode-BoldItalic.woff2 +0 -0
  147. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/woff2/CascadiaCode-Italic.woff2 +0 -0
  148. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/woff2/CascadiaCode-Regular.woff2 +0 -0
  149. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/woff2/CascadiaMono-Bold.woff2 +0 -0
  150. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/woff2/CascadiaMono-BoldItalic.woff2 +0 -0
  151. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/woff2/CascadiaMono-Italic.woff2 +0 -0
  152. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/woff2/CascadiaMono-Regular.woff2 +0 -0
  153. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/static/woff2/README.md +0 -0
  154. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/data/tftp_server.yaml +0 -0
  155. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/dev_requirements.txt +0 -0
  156. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/entry.py +0 -0
  157. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/enum/__init__.py +0 -0
  158. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/enum/registry.py +0 -0
  159. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/enum/types.py +0 -0
  160. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/mapping.py +0 -0
  161. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/message/__init__.py +0 -0
  162. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/message/handlers.py +0 -0
  163. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/message/interface.py +0 -0
  164. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/message/types.py +0 -0
  165. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/metrics/__init__.py +0 -0
  166. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/metrics/channel.py +0 -0
  167. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/metrics/connection.py +0 -0
  168. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/metrics/task.py +0 -0
  169. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/mixins/__init__.py +0 -0
  170. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/mixins/async_command.py +0 -0
  171. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/mixins/enum.py +0 -0
  172. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/mixins/environment.py +0 -0
  173. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/mixins/finalize.py +0 -0
  174. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/mixins/logging.py +0 -0
  175. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/mixins/psutil.py +0 -0
  176. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/mixins/regex.py +0 -0
  177. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/mixins/trig.py +0 -0
  178. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/__init__.py +0 -0
  179. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/apps/__init__.py +0 -0
  180. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/arbiter/__init__.py +0 -0
  181. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/arbiter/config/codec.py +0 -0
  182. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/arbiter/config/util.py +0 -0
  183. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/arbiter/factory/__init__.py +0 -0
  184. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/arbiter/factory/task.py +0 -0
  185. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/arbiter/housekeeping/__init__.py +0 -0
  186. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/arbiter/imports/__init__.py +0 -0
  187. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/arbiter/imports/util.py +0 -0
  188. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/arbiter/info.py +0 -0
  189. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/arbiter/result.py +0 -0
  190. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/arbiter/struct/__init__.py +0 -0
  191. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/arbiter/task.py +0 -0
  192. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/arbiter/tcp/__init__.py +0 -0
  193. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/arbiter/tcp/json.py +0 -0
  194. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/arbiter/udp.py +0 -0
  195. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/arbiter/websocket.py +0 -0
  196. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/backoff.py +0 -0
  197. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/connection.py +0 -0
  198. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/factories/__init__.py +0 -0
  199. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/html/__init__.py +0 -0
  200. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/html/arbiter.py +0 -0
  201. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/html/bootstrap/__init__.py +0 -0
  202. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/html/bootstrap/elements.py +0 -0
  203. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/html/bootstrap/tabs.py +0 -0
  204. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/http/__init__.py +0 -0
  205. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/http/common.py +0 -0
  206. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/http/header.py +0 -0
  207. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/http/request_target.py +0 -0
  208. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/http/response.py +0 -0
  209. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/http/state.py +0 -0
  210. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/http/version.py +0 -0
  211. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/manager.py +0 -0
  212. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/mixin.py +0 -0
  213. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/mtu.py +0 -0
  214. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/__init__.py +0 -0
  215. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/app/__init__.py +0 -0
  216. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/app/base.py +0 -0
  217. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/app/create.py +0 -0
  218. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/app/elements.py +0 -0
  219. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/app/env/__init__.py +0 -0
  220. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/app/env/modal.py +0 -0
  221. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/app/env/settings.py +0 -0
  222. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/app/env/tab/__init__.py +0 -0
  223. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/app/env/tab/controls.py +0 -0
  224. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/app/env/tab/message.py +0 -0
  225. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/app/files.py +0 -0
  226. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/app/landing_page.py +0 -0
  227. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/app/placeholder.py +0 -0
  228. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/app/pyodide.py +0 -0
  229. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/app/sound.py +0 -0
  230. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/app/tab.py +0 -0
  231. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/html.py +0 -0
  232. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/json.py +0 -0
  233. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/markdown.py +0 -0
  234. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/mux.py +0 -0
  235. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/struct/__init__.py +0 -0
  236. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/server/websocket/state.py +0 -0
  237. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/ssl.py +0 -0
  238. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/stream/__init__.py +0 -0
  239. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/stream/base.py +0 -0
  240. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/stream/json/__init__.py +0 -0
  241. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/stream/string.py +0 -0
  242. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/tcp/__init__.py +0 -0
  243. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/tcp/connection.py +0 -0
  244. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/tcp/create.py +0 -0
  245. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/tcp/http/__init__.py +0 -0
  246. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/tcp/protocol.py +0 -0
  247. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/tcp/scpi/__init__.py +0 -0
  248. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/tcp/telnet/__init__.py +0 -0
  249. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/tcp/telnet/codes.py +0 -0
  250. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/tcp/telnet/np_05b.py +0 -0
  251. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/udp/__init__.py +0 -0
  252. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/udp/connection.py +0 -0
  253. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/udp/create.py +0 -0
  254. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/udp/protocol.py +0 -0
  255. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/udp/queue.py +0 -0
  256. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/udp/tftp/__init__.py +0 -0
  257. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/udp/tftp/base.py +0 -0
  258. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/udp/tftp/endpoint.py +0 -0
  259. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/udp/tftp/enums.py +0 -0
  260. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/udp/tftp/io.py +0 -0
  261. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/util.py +0 -0
  262. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/websocket/__init__.py +0 -0
  263. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/net/websocket/connection.py +0 -0
  264. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/noise/__init__.py +0 -0
  265. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/__init__.py +0 -0
  266. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/array/__init__.py +0 -0
  267. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/base.py +0 -0
  268. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/bool.py +0 -0
  269. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/byte_order.py +0 -0
  270. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/evaluation.py +0 -0
  271. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/field/__init__.py +0 -0
  272. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/field/fields.py +0 -0
  273. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/field/manager/__init__.py +0 -0
  274. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/field/manager/base.py +0 -0
  275. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/float.py +0 -0
  276. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/int.py +0 -0
  277. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/scaling.py +0 -0
  278. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/serializable/__init__.py +0 -0
  279. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/serializable/base.py +0 -0
  280. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/serializable/fixed.py +0 -0
  281. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/serializable/framer.py +0 -0
  282. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/serializable/prefixed.py +0 -0
  283. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/string.py +0 -0
  284. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/types/__init__.py +0 -0
  285. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/types/base.py +0 -0
  286. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/types/bool.py +0 -0
  287. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/types/bounds.py +0 -0
  288. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/types/float.py +0 -0
  289. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/primitives/types/int.py +0 -0
  290. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/py.typed +0 -0
  291. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/registry/__init__.py +0 -0
  292. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/registry/bool.py +0 -0
  293. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/registry/item.py +0 -0
  294. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/registry/name.py +0 -0
  295. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/sample/__init__.py +0 -0
  296. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/sample/peer.py +0 -0
  297. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/sample/program.py +0 -0
  298. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/schemas.py +0 -0
  299. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/subprocess/__init__.py +0 -0
  300. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/subprocess/interface.py +0 -0
  301. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/subprocess/peer.py +0 -0
  302. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/subprocess/program.py +0 -0
  303. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/subprocess/protocol.py +0 -0
  304. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/task/__init__.py +0 -0
  305. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/task/asynchronous.py +0 -0
  306. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/task/basic/__init__.py +0 -0
  307. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/task/basic/manager.py +0 -0
  308. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/task/sample.py +0 -0
  309. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/task/trig/__init__.py +0 -0
  310. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/telemetry/__init__.py +0 -0
  311. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/telemetry/sample.py +0 -0
  312. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/tui/__init__.py +0 -0
  313. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/tui/channels/__init__.py +0 -0
  314. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/tui/cursor.py +0 -0
  315. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/tui/mixin.py +0 -0
  316. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/tui/mock.py +0 -0
  317. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/tui/task.py +0 -0
  318. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/ui/__init__.py +0 -0
  319. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/ui/controls.py +0 -0
  320. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy/util.py +0 -0
  321. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy.egg-info/dependency_links.txt +0 -0
  322. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy.egg-info/entry_points.txt +0 -0
  323. {runtimepy-5.15.3 → runtimepy-5.15.5}/runtimepy.egg-info/top_level.txt +0 -0
  324. {runtimepy-5.15.3 → runtimepy-5.15.5}/setup.cfg +0 -0
  325. {runtimepy-5.15.3 → runtimepy-5.15.5}/setup.py +0 -0
  326. {runtimepy-5.15.3 → runtimepy-5.15.5}/tests/test_entry.py +0 -0
  327. {runtimepy-5.15.3 → runtimepy-5.15.5}/tests/test_mapping.py +0 -0
  328. {runtimepy-5.15.3 → runtimepy-5.15.5}/tests/test_resources.py +0 -0
  329. {runtimepy-5.15.3 → runtimepy-5.15.5}/tests/test_util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: runtimepy
3
- Version: 5.15.3
3
+ Version: 5.15.5
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: websockets
21
- Requires-Dist: vcorelib>=3.6.3
22
- Requires-Dist: svgen>=0.8.0
23
- Requires-Dist: aiofiles
24
20
  Requires-Dist: psutil
21
+ Requires-Dist: aiofiles
22
+ Requires-Dist: svgen>=0.8.0
23
+ Requires-Dist: websockets
24
+ Requires-Dist: vcorelib>=3.6.4
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=ed2f5b3731ba189c4a3ec2f2252b622e
54
+ hash=fd0e57419cf9437a64c4f82cae3625f0
55
55
  =====================================
56
56
  -->
57
57
 
58
- # runtimepy ([5.15.3](https://pypi.org/project/runtimepy/))
58
+ # runtimepy ([5.15.5](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=ed2f5b3731ba189c4a3ec2f2252b622e
5
+ hash=fd0e57419cf9437a64c4f82cae3625f0
6
6
  =====================================
7
7
  -->
8
8
 
9
- # runtimepy ([5.15.3](https://pypi.org/project/runtimepy/))
9
+ # runtimepy ([5.15.5](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.3"
7
+ version = "5.15.5"
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=f5155e85b2694b012648fdbe9c12b1cd
4
+ # hash=8ce7abe0f8c0e64d9afc0b5e4de6e2ad
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.3"
13
+ VERSION = "5.15.5"
14
14
 
15
15
  # runtimepy-specific content.
16
16
  METRICS_NAME = "metrics"
@@ -54,6 +54,7 @@ class BaseChannelEnvironment(_NamespaceMixin, FinalizeMixin):
54
54
  fields: _Iterable[_BitFields] = None,
55
55
  namespace: Namespace = None,
56
56
  namespace_delim: str = DEFAULT_DELIM,
57
+ views: dict[str, str] = None,
57
58
  ) -> None:
58
59
  """Initialize this channel environment."""
59
60
 
@@ -105,6 +106,10 @@ class BaseChannelEnvironment(_NamespaceMixin, FinalizeMixin):
105
106
  if values is not None:
106
107
  self.apply(values)
107
108
 
109
+ if not views:
110
+ views = {}
111
+ self.views = views
112
+
108
113
  def __setitem__(self, key: _RegistryKey, value: ChannelValue) -> None:
109
114
  """Mapping-set interface."""
110
115
  return self.set(key, value)
@@ -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:
@@ -42,6 +42,8 @@ ENUMS_FILE = f"{ENUMS_KEY}.json"
42
42
  VALUES_FILE = f"{VALUES_KEY}.json"
43
43
  FIELDS_FILE = f"{FIELDS_KEY}.json"
44
44
  NAMES_FILE = f"{NAMES_KEY}.json"
45
+ VIEWS_KEY = "views"
46
+ # VIEWS_FILE = f"{VIEWS_KEY}.json"
45
47
 
46
48
 
47
49
  class FileChannelEnvironment(_BaseChannelEnvironment):
@@ -64,6 +66,7 @@ class FileChannelEnvironment(_BaseChannelEnvironment):
64
66
  VALUES_KEY: _cast(
65
67
  _JsonObject, self.values(resolve_enum=resolve_enum)
66
68
  ),
69
+ VIEWS_KEY: _cast(_JsonObject, self.views),
67
70
  }
68
71
 
69
72
  def export(
@@ -143,6 +146,7 @@ class FileChannelEnvironment(_BaseChannelEnvironment):
143
146
  enums=enum_reg,
144
147
  values=_cast(_Optional[_ValueMap], data.get(VALUES_KEY)),
145
148
  fields=_fields_from_dict(data[FIELDS_KEY]),
149
+ views=_cast(dict[str, str], data.get(VIEWS_KEY, {})),
146
150
  )
147
151
 
148
152
  # Typically, externally loaded environments should be final at load
@@ -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,10 @@ tasks:
9
47
  a: 1
10
48
  b: 2
11
49
  c: 3
50
+ buttons: *buttons
51
+ views:
52
+ - [zero, "\\.0\\."]
53
+ - [one, "\\.1\\."]
12
54
  markdown: |
13
55
  # This is a Test
14
56
 
@@ -29,6 +71,9 @@ tasks:
29
71
  - name: wave3
30
72
  factory: sinusoid
31
73
  period_s: 0.03
74
+ config:
75
+ views:
76
+ - [trig, sin cos]
32
77
  markdown: |
33
78
  # Markdown for wave3
34
79
 
@@ -43,23 +88,6 @@ tasks:
43
88
  # Drive interactions with runtime entities that won't otherwise be polled.
44
89
  - {name: app, factory: SampleApp, period_s: 0.25}
45
90
 
46
- # UDP JSON clients.
47
- clients:
48
- - factory: udp_json
49
- name: udp_json_client
50
- defer: true
51
- kwargs:
52
- remote_addr: [localhost, "$udp_json"]
53
- markdown: |
54
- # `udp_json_client`
55
-
56
- Connects to `udp_json_server`.
57
-
58
- - factory: udp_json
59
- name: udp_json_server
60
- kwargs:
61
- local_addr: [localhost, "$udp_json"]
62
-
63
91
  # Add some sample structs.
64
92
  structs:
65
93
  - name: example.struct1
@@ -70,6 +98,8 @@ structs:
70
98
  b: 2
71
99
  c: 3
72
100
 
101
+ buttons: *buttons
102
+
73
103
  markdown: |
74
104
  # Docs for `example.struct1`
75
105
 
@@ -56,6 +56,10 @@ class ChannelTable {
56
56
 
57
57
  if (Number.isInteger(val)) {
58
58
  /* Handle integer formatting. */
59
+ } else if (typeof val == "boolean") {
60
+ /* Use glyphs for booleans. */
61
+ val = val ? '<i class="bi bi-circle-fill"></i>'
62
+ : '<i class="bi bi-circle"></i>';
59
63
  } else {
60
64
  /* Handle floating-point numbers. */
61
65
  let checkFloat = Number.parseFloat(val);
@@ -263,6 +263,19 @@ class TabInterface {
263
263
  this.updateChannelStyles(this.channelFilter.value);
264
264
  };
265
265
  }
266
+
267
+ /* Initialize channel view dropdown. */
268
+ let channelView = this.query("#filter-view");
269
+ if (channelView) {
270
+ channelView.onchange = () => {
271
+ if (!channelView.value || channelView.value == '-') {
272
+ this.channelFilter.value = "";
273
+ } else {
274
+ this.channelFilter.value = channelView.value;
275
+ }
276
+ this.updateChannelStyles(this.channelFilter.value);
277
+ };
278
+ }
266
279
  }
267
280
 
268
281
  setHandler(elem) {
@@ -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
  }
@@ -53,8 +53,10 @@ function isModifierKeyEvent(event) {
53
53
  }
54
54
 
55
55
  function ignoreFilterKeyEvent(event) {
56
- // home end pg up pg down delete f keys
57
- return isModifierKeyEvent(event) || event.key == "Tab";
56
+ return isModifierKeyEvent(event) || event.key == "Tab" ||
57
+ (event.key.startsWith("F") && event.key.length > 1) ||
58
+ event.key.startsWith("Del") || event.key == "Home" ||
59
+ event.key == "End" || event.key == "PageUp" || event.key == "PageDown";
58
60
  }
59
61
 
60
62
  function globalKeyEvent(event) {
@@ -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
@@ -3,6 +3,8 @@ includes:
3
3
  - has_factory.yaml
4
4
  - has_name.yaml
5
5
  - has_markdown.yaml
6
+ - has_views.yaml
7
+ - has_buttons.yaml
6
8
 
7
9
  properties:
8
10
  defer:
@@ -27,14 +27,7 @@ properties:
27
27
  $ref: package://runtimepy/schemas/StructConfig.yaml
28
28
 
29
29
  commands:
30
- type: array
31
- items:
32
- type: array
33
- minItems: 2
34
- maxItems: 2
35
- items:
36
- - type: string
37
- - type: string
30
+ $ref: package://runtimepy/schemas/TwoTupleArray.yaml
38
31
 
39
32
  tasks:
40
33
  type: array
@@ -4,6 +4,7 @@ includes:
4
4
  - has_name.yaml
5
5
  - has_config.yaml
6
6
  - has_markdown.yaml
7
+ - has_views.yaml
7
8
 
8
9
  properties:
9
10
  program:
@@ -0,0 +1,9 @@
1
+ ---
2
+ type: array
3
+ items:
4
+ type: array
5
+ minItems: 2
6
+ maxItems: 2
7
+ items:
8
+ - type: string
9
+ - type: string
@@ -0,0 +1,6 @@
1
+ ---
2
+ properties:
3
+ buttons:
4
+ type: array
5
+ items:
6
+ $ref: package://runtimepy/schemas/Button.yaml
@@ -0,0 +1,4 @@
1
+ ---
2
+ properties:
3
+ views:
4
+ $ref: package://runtimepy/schemas/TwoTupleArray.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[
@@ -147,6 +148,8 @@ class BaseConnectionArbiter(_NamespaceMixin, _LoggerMixin, TuiMixin):
147
148
  self._ports: dict[str, int] = {}
148
149
 
149
150
  self._commands: list[tuple[str, str]] = []
151
+ self._views: dict[str, dict[str, str]] = {}
152
+ self._buttons: dict[str, list[ActionButton]] = {}
150
153
 
151
154
  self._init()
152
155
 
@@ -156,6 +159,16 @@ class BaseConnectionArbiter(_NamespaceMixin, _LoggerMixin, TuiMixin):
156
159
  def _register_connection(self, connection: _Connection, name: str) -> None:
157
160
  """Perform connection registration."""
158
161
 
162
+ # Handle views.
163
+ if name in self._views:
164
+ connection.env.views.update(self._views[name])
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
+
159
172
  self._connections[name] = connection
160
173
  self.manager.queue.put_nowait(connection)
161
174
  connection.logger.info("Registered as '%s'.", name)
@@ -165,6 +178,8 @@ class BaseConnectionArbiter(_NamespaceMixin, _LoggerMixin, TuiMixin):
165
178
  connection: _Union[_Connection, _Awaitable[_Connection]],
166
179
  *names: str,
167
180
  delim: str = None,
181
+ views: dict[str, str] = None,
182
+ buttons: list[ActionButton] = None,
168
183
  ) -> bool:
169
184
  """Attempt to register a connection object."""
170
185
 
@@ -173,6 +188,11 @@ class BaseConnectionArbiter(_NamespaceMixin, _LoggerMixin, TuiMixin):
173
188
  with self.names_pushed(*names):
174
189
  name = self.namespace(delim=delim)
175
190
 
191
+ if views:
192
+ self._views[name] = views
193
+ if buttons:
194
+ self._buttons[name] = buttons
195
+
176
196
  if (
177
197
  name not in self._connections
178
198
  and name not in self._deferred_connections
@@ -170,7 +170,6 @@ class ConfigConnectionArbiter(_ImportConnectionArbiter):
170
170
  kwargs = dict_resolve_env_vars(
171
171
  client.get("kwargs", {}), env=self._ports # type: ignore
172
172
  )
173
- kwargs.setdefault("markdown", client.get("markdown"))
174
173
 
175
174
  assert await self.factory_client(
176
175
  factory,
@@ -179,6 +178,9 @@ class ConfigConnectionArbiter(_ImportConnectionArbiter):
179
178
  defer=client["defer"],
180
179
  # Perform some known fixes for common keyword arguments.
181
180
  **fix_kwargs(kwargs),
181
+ views=client.get("views"),
182
+ markdown=client.get("markdown"),
183
+ buttons=client.get("buttons", []),
182
184
  ), f"Couldn't register client '{name}' ({factory})!"
183
185
 
184
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:
@@ -89,12 +90,19 @@ class FactoryConnectionArbiter(_BaseConnectionArbiter):
89
90
  if factory in self._conn_factories:
90
91
  factory_inst = self._conn_factories[factory]
91
92
 
93
+ views = kwargs.pop("views", {})
94
+ buttons = ActionButton.from_top_level(kwargs.pop("buttons", []))
95
+
92
96
  conn = factory_inst.client(name, *args, **kwargs)
93
97
  if not defer:
94
98
  conn = await conn # type: ignore
95
99
 
96
100
  result = self.register_connection(
97
- conn, *self._conn_names[factory_inst], name
101
+ conn,
102
+ *self._conn_names[factory_inst],
103
+ name,
104
+ views=views,
105
+ buttons=buttons,
98
106
  )
99
107
 
100
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(
@@ -80,6 +80,22 @@ def enum_dropdown(
80
80
  TABLE_BUTTON_CLASSES = ("border-top-0", "border-bottom-0")
81
81
 
82
82
 
83
+ def views_dropdown(parent: Element, command: ChannelCommandProcessor) -> None:
84
+ """Dropdown menu for channel environment views."""
85
+
86
+ select = select_element(
87
+ parent=div(
88
+ tag="th", parent=parent, class_str="p-0 channel-views-min-width"
89
+ ),
90
+ id="filter-view",
91
+ title="Canonical channel filters.",
92
+ ).add_class("border-end-0", "w-100")
93
+ div(tag="option", value="", text="-", parent=select)
94
+ div(tag="option", value="^$", text="hide", parent=select)
95
+ for text, value in command.env.views.items():
96
+ div(tag="option", value=value, text=text, parent=select)
97
+
98
+
83
99
  def channel_table_header(
84
100
  parent: Element, command: ChannelCommandProcessor
85
101
  ) -> None:
@@ -105,7 +121,11 @@ def channel_table_header(
105
121
  ).add_class(*TABLE_BUTTON_CLASSES)
106
122
 
107
123
  _, label, box = input_box(
108
- div(tag="th", parent=ctl_row, colspan="2", class_str="p-0"),
124
+ div(
125
+ tag="th",
126
+ parent=ctl_row,
127
+ class_str="p-0 border-end-0 channel-filter-min-width",
128
+ ),
109
129
  description="Channel name filter.",
110
130
  pattern=".* ! @ $",
111
131
  label="filter",
@@ -114,7 +134,9 @@ def channel_table_header(
114
134
  spellcheck="false",
115
135
  )
116
136
  label.add_class("border-top-0", "border-bottom-0")
117
- box.add_class("border-top-0", "border-bottom-0")
137
+ box.add_class("border-top-0", "border-bottom-0", "border-end-0")
138
+
139
+ views_dropdown(ctl_row, command)
118
140
 
119
141
  cell = flex(
120
142
  parent=div(tag="th", parent=ctl_row, colspan="2", class_str="p-0")
@@ -124,7 +146,6 @@ def channel_table_header(
124
146
  select = select_element(
125
147
  parent=cell, id="custom-commands", title="Custom command selector."
126
148
  )
127
- select.add_class("border-start-0")
128
149
 
129
150
  if command.custom_commands:
130
151
  for key in command.custom_commands:
@@ -141,12 +162,7 @@ def channel_table_header(
141
162
  tooltip="Send selected command (left dropdown).",
142
163
  ).add_class(*TABLE_BUTTON_CLASSES)
143
164
  else:
144
- div(
145
- tag="option",
146
- parent=select,
147
- value="noop",
148
- text="no custom commands",
149
- )
165
+ div(tag="option", parent=select, value="noop", text="-")
150
166
  select.booleans.add("disabled")
151
167
 
152
168
  # Button for 'reset all defaults' if this tab has more than one channel
@@ -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(
@@ -45,10 +46,12 @@ class RuntimeStructBase(
45
46
  self.set_markdown(config=config, markdown=markdown, package=PKG_NAME)
46
47
  LoggerMixinLevelControl.__init__(self, logger=_getLogger(self.name))
47
48
  ChannelEnvironmentMixin.__init__(self)
49
+ self.env.views.update(config.get("views", {})) # type: ignore
48
50
  if self.log_level_channel:
49
51
  self.setup_level_channel(self.env)
50
52
  self.command = ChannelCommandProcessor(self.env, self.logger)
51
53
  self.config = config
54
+ self.command.buttons.extend(ActionButton.from_top_level(self.config))
52
55
 
53
56
  async def poll(args: Namespace, __: Optional[FieldOrChannel]) -> None:
54
57
  """Handle a test command."""