runtimepy 5.6.3__tar.gz → 5.6.4__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 (288) hide show
  1. {runtimepy-5.6.3/runtimepy.egg-info → runtimepy-5.6.4}/PKG-INFO +8 -7
  2. {runtimepy-5.6.3 → runtimepy-5.6.4}/README.md +2 -2
  3. {runtimepy-5.6.3 → runtimepy-5.6.4}/pyproject.toml +3 -3
  4. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/__init__.py +2 -2
  5. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/channel/environment/command/__init__.py +1 -1
  6. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/channel/environment/telemetry.py +3 -1
  7. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/css/bootstrap_extra.css +1 -0
  8. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/css/main.css +4 -0
  9. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/dummy_load.yaml +34 -1
  10. runtimepy-5.6.4/runtimepy/data/md/Connection.md +3 -0
  11. runtimepy-5.6.4/runtimepy/data/md/PeriodicTask.md +3 -0
  12. runtimepy-5.6.4/runtimepy/data/md/RuntimeStruct.md +3 -0
  13. runtimepy-5.6.4/runtimepy/data/md/RuntimepyPeer.md +3 -0
  14. runtimepy-5.6.4/runtimepy/data/md/SinusoidTask.md +20 -0
  15. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/schemas/ClientConnectionConfig.yaml +1 -0
  16. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/schemas/PeerProcessConfig.yaml +1 -0
  17. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/schemas/TaskConfig.yaml +1 -0
  18. runtimepy-5.6.4/runtimepy/data/schemas/has_markdown.yaml +4 -0
  19. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/mapping.py +1 -1
  20. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/message/interface.py +2 -2
  21. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/mixins/environment.py +10 -4
  22. runtimepy-5.6.4/runtimepy/mixins/logging.py +110 -0
  23. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/arbiter/base.py +13 -3
  24. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/arbiter/config/__init__.py +6 -2
  25. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/arbiter/imports/__init__.py +5 -5
  26. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/arbiter/imports/util.py +3 -1
  27. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/connection.py +7 -1
  28. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/http/common.py +5 -0
  29. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/http/header.py +5 -1
  30. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/http/response.py +1 -1
  31. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/__init__.py +3 -1
  32. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/bootstrap/elements.py +38 -1
  33. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/env/__init__.py +69 -19
  34. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/env/tab/base.py +5 -1
  35. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/env/tab/html.py +6 -6
  36. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/struct/__init__.py +1 -2
  37. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/websocket/state.py +3 -1
  38. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/tcp/connection.py +14 -4
  39. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/tcp/http/__init__.py +9 -7
  40. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/udp/connection.py +11 -4
  41. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/udp/tftp/__init__.py +1 -2
  42. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/websocket/connection.py +10 -5
  43. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/requirements.txt +2 -1
  44. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/struct/__init__.py +12 -2
  45. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/subprocess/interface.py +17 -4
  46. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/subprocess/peer.py +20 -6
  47. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/task/basic/periodic.py +7 -1
  48. runtimepy-5.6.4/runtimepy/util.py +18 -0
  49. {runtimepy-5.6.3 → runtimepy-5.6.4/runtimepy.egg-info}/PKG-INFO +8 -7
  50. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy.egg-info/SOURCES.txt +6 -0
  51. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy.egg-info/requires.txt +3 -2
  52. {runtimepy-5.6.3 → runtimepy-5.6.4}/setup.py +2 -2
  53. runtimepy-5.6.3/runtimepy/mixins/logging.py +0 -57
  54. runtimepy-5.6.3/runtimepy/util.py +0 -99
  55. {runtimepy-5.6.3 → runtimepy-5.6.4}/LICENSE +0 -0
  56. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/__main__.py +0 -0
  57. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/app.py +0 -0
  58. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/channel/__init__.py +0 -0
  59. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/channel/environment/__init__.py +0 -0
  60. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/channel/environment/array.py +0 -0
  61. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/channel/environment/base.py +0 -0
  62. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/channel/environment/command/parser.py +0 -0
  63. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/channel/environment/command/processor.py +0 -0
  64. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/channel/environment/command/result.py +0 -0
  65. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/channel/environment/create.py +0 -0
  66. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/channel/environment/file.py +0 -0
  67. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/channel/environment/sample.py +0 -0
  68. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/channel/event/__init__.py +0 -0
  69. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/channel/event/header.py +0 -0
  70. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/channel/registry.py +0 -0
  71. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/codec/__init__.py +0 -0
  72. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/codec/protocol/__init__.py +0 -0
  73. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/codec/protocol/base.py +0 -0
  74. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/codec/protocol/json.py +0 -0
  75. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/codec/system/__init__.py +0 -0
  76. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/commands/__init__.py +0 -0
  77. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/commands/all.py +0 -0
  78. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/commands/arbiter.py +0 -0
  79. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/commands/common.py +0 -0
  80. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/commands/mtu.py +0 -0
  81. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/commands/server.py +0 -0
  82. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/commands/task.py +0 -0
  83. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/commands/tftp.py +0 -0
  84. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/commands/tui.py +0 -0
  85. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/control/__init__.py +0 -0
  86. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/control/env/__init__.py +0 -0
  87. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/control/source.py +0 -0
  88. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/control/step.py +0 -0
  89. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/browser.yaml +0 -0
  90. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/factories.yaml +0 -0
  91. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/favicon.ico +0 -0
  92. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/DataConnection.js +0 -0
  93. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/JsonConnection.js +0 -0
  94. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/audio.js +0 -0
  95. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/classes/App.js +0 -0
  96. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/classes/ChannelTable.js +0 -0
  97. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/classes/DataConnection.js +0 -0
  98. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/classes/JsonConnection.js +0 -0
  99. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/classes/OverlayManager.js +0 -0
  100. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/classes/Plot.js +0 -0
  101. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/classes/PlotDrawer.js +0 -0
  102. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/classes/PlotManager.js +0 -0
  103. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/classes/PlotModalManager.js +0 -0
  104. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/classes/PointBuffer.js +0 -0
  105. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/classes/PointManager.js +0 -0
  106. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/classes/TabFilter.js +0 -0
  107. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/classes/TabInterface.js +0 -0
  108. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/classes/UnitSystem.js +0 -0
  109. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/classes/WindowHashManager.js +0 -0
  110. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/classes/WorkerInterface.js +0 -0
  111. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/events.js +0 -0
  112. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/init.js +0 -0
  113. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/main.js +0 -0
  114. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/tab/env.js +0 -0
  115. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/tab/sound.js +0 -0
  116. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/third-party/webgl-debug.js +0 -0
  117. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/unused/pyodide.js +0 -0
  118. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/util.js +0 -0
  119. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/js/worker.js +0 -0
  120. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/sample_telemetry.yaml +0 -0
  121. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/schemas/BitFields.yaml +0 -0
  122. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/schemas/Channel.yaml +0 -0
  123. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/schemas/ChannelCommand.yaml +0 -0
  124. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/schemas/ChannelRegistry.yaml +0 -0
  125. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/schemas/ConnectionArbiterConfig.yaml +0 -0
  126. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/schemas/EnumRegistry.yaml +0 -0
  127. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/schemas/FindFile.yaml +0 -0
  128. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/schemas/RuntimeEnum.yaml +0 -0
  129. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/schemas/ServerConnectionConfig.yaml +0 -0
  130. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/schemas/StructConfig.yaml +0 -0
  131. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/schemas/channel_controls.yaml +0 -0
  132. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/schemas/has_config.yaml +0 -0
  133. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/schemas/has_factory.yaml +0 -0
  134. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/schemas/has_name.yaml +0 -0
  135. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/schemas/has_request_flag.yaml +0 -0
  136. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/server.yaml +0 -0
  137. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/server_base.yaml +0 -0
  138. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/server_dev.yaml +0 -0
  139. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/data/tftp_server.yaml +0 -0
  140. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/dev_requirements.txt +0 -0
  141. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/entry.py +0 -0
  142. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/enum/__init__.py +0 -0
  143. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/enum/registry.py +0 -0
  144. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/enum/types.py +0 -0
  145. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/message/__init__.py +0 -0
  146. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/message/handlers.py +0 -0
  147. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/message/types.py +0 -0
  148. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/metrics/__init__.py +0 -0
  149. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/metrics/channel.py +0 -0
  150. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/metrics/connection.py +0 -0
  151. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/metrics/task.py +0 -0
  152. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/mixins/__init__.py +0 -0
  153. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/mixins/async_command.py +0 -0
  154. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/mixins/enum.py +0 -0
  155. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/mixins/finalize.py +0 -0
  156. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/mixins/psutil.py +0 -0
  157. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/mixins/regex.py +0 -0
  158. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/mixins/trig.py +0 -0
  159. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/__init__.py +0 -0
  160. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/apps/__init__.py +0 -0
  161. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/arbiter/__init__.py +0 -0
  162. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/arbiter/config/codec.py +0 -0
  163. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/arbiter/config/util.py +0 -0
  164. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/arbiter/factory/__init__.py +0 -0
  165. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/arbiter/factory/connection.py +0 -0
  166. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/arbiter/factory/task.py +0 -0
  167. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/arbiter/housekeeping/__init__.py +0 -0
  168. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/arbiter/info.py +0 -0
  169. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/arbiter/result.py +0 -0
  170. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/arbiter/struct/__init__.py +0 -0
  171. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/arbiter/task.py +0 -0
  172. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/arbiter/tcp/__init__.py +0 -0
  173. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/arbiter/tcp/json.py +0 -0
  174. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/arbiter/udp.py +0 -0
  175. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/arbiter/websocket.py +0 -0
  176. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/backoff.py +0 -0
  177. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/factories/__init__.py +0 -0
  178. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/http/__init__.py +0 -0
  179. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/http/request_target.py +0 -0
  180. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/http/state.py +0 -0
  181. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/http/version.py +0 -0
  182. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/manager.py +0 -0
  183. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/mixin.py +0 -0
  184. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/mtu.py +0 -0
  185. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/__init__.py +0 -0
  186. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/base.py +0 -0
  187. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/bootstrap/__init__.py +0 -0
  188. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/bootstrap/tabs.py +0 -0
  189. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/create.py +0 -0
  190. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/elements.py +0 -0
  191. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/env/modal.py +0 -0
  192. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/env/settings.py +0 -0
  193. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/env/tab/__init__.py +0 -0
  194. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/env/tab/controls.py +0 -0
  195. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/env/tab/message.py +0 -0
  196. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/env/widgets.py +0 -0
  197. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/files.py +0 -0
  198. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/landing_page.py +0 -0
  199. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/placeholder.py +0 -0
  200. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/pyodide.py +0 -0
  201. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/sound.py +0 -0
  202. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/app/tab.py +0 -0
  203. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/html.py +0 -0
  204. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/json.py +0 -0
  205. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/server/websocket/__init__.py +0 -0
  206. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/ssl.py +0 -0
  207. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/stream/__init__.py +0 -0
  208. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/stream/base.py +0 -0
  209. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/stream/json/__init__.py +0 -0
  210. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/stream/string.py +0 -0
  211. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/tcp/__init__.py +0 -0
  212. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/tcp/create.py +0 -0
  213. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/tcp/protocol.py +0 -0
  214. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/tcp/scpi/__init__.py +0 -0
  215. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/tcp/telnet/__init__.py +0 -0
  216. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/tcp/telnet/codes.py +0 -0
  217. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/tcp/telnet/np_05b.py +0 -0
  218. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/udp/__init__.py +0 -0
  219. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/udp/create.py +0 -0
  220. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/udp/protocol.py +0 -0
  221. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/udp/queue.py +0 -0
  222. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/udp/tftp/base.py +0 -0
  223. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/udp/tftp/endpoint.py +0 -0
  224. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/udp/tftp/enums.py +0 -0
  225. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/udp/tftp/io.py +0 -0
  226. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/util.py +0 -0
  227. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/net/websocket/__init__.py +0 -0
  228. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/noise/__init__.py +0 -0
  229. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/__init__.py +0 -0
  230. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/array/__init__.py +0 -0
  231. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/base.py +0 -0
  232. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/bool.py +0 -0
  233. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/byte_order.py +0 -0
  234. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/evaluation.py +0 -0
  235. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/field/__init__.py +0 -0
  236. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/field/fields.py +0 -0
  237. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/field/manager/__init__.py +0 -0
  238. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/field/manager/base.py +0 -0
  239. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/float.py +0 -0
  240. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/int.py +0 -0
  241. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/scaling.py +0 -0
  242. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/serializable/__init__.py +0 -0
  243. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/serializable/base.py +0 -0
  244. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/serializable/fixed.py +0 -0
  245. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/serializable/framer.py +0 -0
  246. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/serializable/prefixed.py +0 -0
  247. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/string.py +0 -0
  248. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/types/__init__.py +0 -0
  249. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/types/base.py +0 -0
  250. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/types/bool.py +0 -0
  251. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/types/bounds.py +0 -0
  252. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/types/float.py +0 -0
  253. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/primitives/types/int.py +0 -0
  254. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/py.typed +0 -0
  255. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/registry/__init__.py +0 -0
  256. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/registry/bool.py +0 -0
  257. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/registry/item.py +0 -0
  258. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/registry/name.py +0 -0
  259. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/sample/__init__.py +0 -0
  260. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/sample/peer.py +0 -0
  261. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/sample/program.py +0 -0
  262. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/schemas.py +0 -0
  263. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/subprocess/__init__.py +0 -0
  264. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/subprocess/program.py +0 -0
  265. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/subprocess/protocol.py +0 -0
  266. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/task/__init__.py +0 -0
  267. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/task/asynchronous.py +0 -0
  268. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/task/basic/__init__.py +0 -0
  269. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/task/basic/manager.py +0 -0
  270. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/task/sample.py +0 -0
  271. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/task/trig/__init__.py +0 -0
  272. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/telemetry/__init__.py +0 -0
  273. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/telemetry/sample.py +0 -0
  274. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/tui/__init__.py +0 -0
  275. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/tui/channels/__init__.py +0 -0
  276. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/tui/cursor.py +0 -0
  277. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/tui/mixin.py +0 -0
  278. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/tui/mock.py +0 -0
  279. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/tui/task.py +0 -0
  280. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/ui/__init__.py +0 -0
  281. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy/ui/controls.py +0 -0
  282. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy.egg-info/dependency_links.txt +0 -0
  283. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy.egg-info/entry_points.txt +0 -0
  284. {runtimepy-5.6.3 → runtimepy-5.6.4}/runtimepy.egg-info/top_level.txt +0 -0
  285. {runtimepy-5.6.3 → runtimepy-5.6.4}/setup.cfg +0 -0
  286. {runtimepy-5.6.3 → runtimepy-5.6.4}/tests/test_entry.py +0 -0
  287. {runtimepy-5.6.3 → runtimepy-5.6.4}/tests/test_mapping.py +0 -0
  288. {runtimepy-5.6.3 → runtimepy-5.6.4}/tests/test_resources.py +0 -0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: runtimepy
3
- Version: 5.6.3
3
+ Version: 5.6.4
4
4
  Summary: A framework for implementing Python services.
5
5
  Home-page: https://github.com/vkottler/runtimepy
6
6
  Author: Vaughn Kottler
7
- Author-email: Vaughn Kottler <vaughnkottler@gmail.com>
8
- Maintainer-email: Vaughn Kottler <vaughnkottler@gmail.com>
7
+ Author-email: Vaughn Kottler <vaughn@libre-embedded.com>
8
+ Maintainer-email: Vaughn Kottler <vaughn@libre-embedded.com>
9
9
  Classifier: Programming Language :: Python :: 3.11
10
10
  Classifier: Programming Language :: Python :: 3.12
11
11
  Classifier: Operating System :: Microsoft :: Windows
@@ -17,10 +17,11 @@ Classifier: License :: OSI Approved :: MIT License
17
17
  Requires-Python: >=3.11
18
18
  Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
- Requires-Dist: vcorelib>=3.3.1
20
+ Requires-Dist: websockets
21
21
  Requires-Dist: svgen>=0.6.8
22
+ Requires-Dist: vcorelib>=3.4.1
22
23
  Requires-Dist: psutil
23
- Requires-Dist: websockets
24
+ Requires-Dist: aiofiles
24
25
  Provides-Extra: test
25
26
  Requires-Dist: pylint; extra == "test"
26
27
  Requires-Dist: flake8; extra == "test"
@@ -44,11 +45,11 @@ Requires-Dist: uvloop; (sys_platform != "win32" and sys_platform != "cygwin") an
44
45
  =====================================
45
46
  generator=datazen
46
47
  version=3.1.4
47
- hash=ac4d0a4097094aeb4e3f43c5f1128115
48
+ hash=41c5a2511c80b2cbbaee668bb6a75bd2
48
49
  =====================================
49
50
  -->
50
51
 
51
- # runtimepy ([5.6.3](https://pypi.org/project/runtimepy/))
52
+ # runtimepy ([5.6.4](https://pypi.org/project/runtimepy/))
52
53
 
53
54
  [![python](https://img.shields.io/pypi/pyversions/runtimepy.svg)](https://pypi.org/project/runtimepy/)
54
55
  ![Build Status](https://github.com/vkottler/runtimepy/workflows/Python%20Package/badge.svg)
@@ -2,11 +2,11 @@
2
2
  =====================================
3
3
  generator=datazen
4
4
  version=3.1.4
5
- hash=ac4d0a4097094aeb4e3f43c5f1128115
5
+ hash=41c5a2511c80b2cbbaee668bb6a75bd2
6
6
  =====================================
7
7
  -->
8
8
 
9
- # runtimepy ([5.6.3](https://pypi.org/project/runtimepy/))
9
+ # runtimepy ([5.6.4](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/vkottler/runtimepy/workflows/Python%20Package/badge.svg)
@@ -4,15 +4,15 @@ build-backend = "setuptools.build_meta:__legacy__"
4
4
 
5
5
  [project]
6
6
  name = "runtimepy"
7
- version = "5.6.3"
7
+ version = "5.6.4"
8
8
  description = "A framework for implementing Python services."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
11
11
  authors = [
12
- {name = "Vaughn Kottler", email = "vaughnkottler@gmail.com"}
12
+ {name = "Vaughn Kottler", email = "vaughn@libre-embedded.com"}
13
13
  ]
14
14
  maintainers = [
15
- {name = "Vaughn Kottler", email = "vaughnkottler@gmail.com"}
15
+ {name = "Vaughn Kottler", email = "vaughn@libre-embedded.com"}
16
16
  ]
17
17
  classifiers = [
18
18
  "Programming Language :: Python :: 3.11",
@@ -1,7 +1,7 @@
1
1
  # =====================================
2
2
  # generator=datazen
3
3
  # version=3.1.4
4
- # hash=9547492b6c819241db9f6c010450b6ce
4
+ # hash=beefe82269955725f177c01474f7cea1
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.6.3"
13
+ VERSION = "5.6.4"
14
14
 
15
15
  # runtimepy-specific content.
16
16
  METRICS_NAME = "metrics"
@@ -15,6 +15,7 @@ from vcorelib import DEFAULT_ENCODING
15
15
  from vcorelib.io import ARBITER, JsonObject
16
16
  from vcorelib.logging import DEFAULT_TIME_FORMAT, LoggerMixin
17
17
  from vcorelib.math import default_time_ns, nano_str
18
+ from vcorelib.names import name_search
18
19
 
19
20
  # internal
20
21
  from runtimepy.channel.environment import ChannelEnvironment
@@ -26,7 +27,6 @@ from runtimepy.channel.environment.command.processor import (
26
27
  )
27
28
  from runtimepy.channel.registry import ParsedEvent
28
29
  from runtimepy.mapping import DEFAULT_PATTERN
29
- from runtimepy.util import name_search
30
30
 
31
31
  # Declared so we re-export FieldOrChannel after moving where it's declared.
32
32
  __all__ = [
@@ -6,6 +6,9 @@ A module implementing channel-environment telemetry registration.
6
6
  from contextlib import ExitStack, contextmanager
7
7
  from typing import BinaryIO, Iterator, Optional, cast
8
8
 
9
+ # third-party
10
+ from vcorelib.names import name_search
11
+
9
12
  # internal
10
13
  from runtimepy.channel.environment.base import (
11
14
  BaseChannelEnvironment as _BaseChannelEnvironment,
@@ -14,7 +17,6 @@ from runtimepy.channel.event import PrimitiveEvent
14
17
  from runtimepy.channel.registry import ParsedEvent
15
18
  from runtimepy.mapping import DEFAULT_PATTERN
16
19
  from runtimepy.metrics.channel import ChannelMetrics
17
- from runtimepy.util import name_search
18
20
 
19
21
 
20
22
  class TelemetryChannelEnvironment(_BaseChannelEnvironment):
@@ -42,6 +42,7 @@
42
42
 
43
43
  .table-container {
44
44
  overflow-x: scroll;
45
+ min-height: fit-content;
45
46
  }
46
47
 
47
48
  .channel-column {
@@ -17,6 +17,10 @@ body > :first-child {
17
17
  height: 100%;
18
18
  }
19
19
 
20
+ #runtimepy-tabs {
21
+ width: min-content;
22
+ }
23
+
20
24
  #runtimepy-splash {
21
25
  position: fixed;
22
26
  top: 0;
@@ -9,7 +9,19 @@ tasks:
9
9
  # Sinusoids.
10
10
  - {name: wave1, factory: sinusoid, period_s: 0.01}
11
11
  - {name: wave2, factory: sinusoid, period_s: 0.02}
12
- - {name: wave3, factory: sinusoid, period_s: 0.03}
12
+ - name: wave3
13
+ factory: sinusoid
14
+ period_s: 0.03
15
+ markdown: |
16
+ # Markdown for wave3
17
+
18
+ * list element 1
19
+ * list element 2
20
+ * list element 3
21
+
22
+ To be continued.
23
+
24
+ `peace`
13
25
 
14
26
  # Drive interactions with runtime entities that won't otherwise be polled.
15
27
  - {name: app, factory: SampleApp, period_s: 0.25}
@@ -21,6 +33,11 @@ clients:
21
33
  defer: true
22
34
  kwargs:
23
35
  remote_addr: [localhost, "$udp_json"]
36
+ markdown: |
37
+ # `udp_json_client`
38
+
39
+ Connects to `udp_json_server`.
40
+
24
41
  - factory: udp_json
25
42
  name: udp_json_server
26
43
  kwargs:
@@ -36,8 +53,19 @@ structs:
36
53
  b: 2
37
54
  c: 3
38
55
 
56
+ markdown: |
57
+ # Docs for `example.struct1`
58
+
59
+ Should be shown for peer process as well?
60
+
39
61
  - name: struct2
40
62
  factory: sample_struct
63
+ config:
64
+ markdown: |
65
+ # `struct2`
66
+
67
+ One of the structs of all time.
68
+
41
69
  - name: struct3
42
70
  factory: sample_struct
43
71
 
@@ -46,6 +74,11 @@ processes:
46
74
  - name: proc1
47
75
  factory: sample_peer
48
76
 
77
+ markdown: |
78
+ # Markdown for `proc1`
79
+
80
+ A process that
81
+
49
82
  # The peer itself runs an arbiter process.
50
83
  config:
51
84
  includes:
@@ -0,0 +1,3 @@
1
+ # Connections
2
+
3
+ To be continued.
@@ -0,0 +1,3 @@
1
+ # Periodic Tasks
2
+
3
+ To be continued.
@@ -0,0 +1,3 @@
1
+ # Runtime Structures
2
+
3
+ To be continued.
@@ -0,0 +1,3 @@
1
+ # Peer Programs
2
+
3
+ To be continued.
@@ -0,0 +1,20 @@
1
+ # Sinusoid Tasks
2
+
3
+ ## Intent
4
+
5
+ These tasks compute
6
+ [`math.sin`](https://docs.python.org/3/library/math.html#math.sin) and
7
+ [`math.cos`](https://docs.python.org/3/library/math.html#math.cos) on every
8
+ iteration, which advances one "step" per dispatch where the "step angle"
9
+ advanced depends on the `steps` control.
10
+
11
+ Once the current "step angle" is computed, controls `amplitude` and phase
12
+ angles are considered for final `sin` and `cos` channel values.
13
+
14
+ ## Discussion
15
+
16
+ * Is it worth adding a `tan` channel that computes
17
+ [`math.tan`](https://docs.python.org/3/library/math.html#math.tan) and/or other
18
+ trigonometric functions?
19
+ * Is it worth adding a "number of steps" control, such that one task iteration
20
+ could advance multiple waveform steps?
@@ -2,6 +2,7 @@
2
2
  includes:
3
3
  - has_factory.yaml
4
4
  - has_name.yaml
5
+ - has_markdown.yaml
5
6
 
6
7
  properties:
7
8
  defer:
@@ -3,6 +3,7 @@ includes:
3
3
  - has_factory.yaml
4
4
  - has_name.yaml
5
5
  - has_config.yaml
6
+ - has_markdown.yaml
6
7
 
7
8
  required: [program]
8
9
 
@@ -2,6 +2,7 @@
2
2
  includes:
3
3
  - has_factory.yaml
4
4
  - has_name.yaml
5
+ - has_markdown.yaml
5
6
 
6
7
  properties:
7
8
  period_s:
@@ -0,0 +1,4 @@
1
+ ---
2
+ properties:
3
+ markdown:
4
+ type: string
@@ -13,10 +13,10 @@ from typing import cast as _cast
13
13
 
14
14
  # third-party
15
15
  from vcorelib.logging import LoggerMixin
16
+ from vcorelib.names import name_search
16
17
 
17
18
  # internal
18
19
  from runtimepy.mixins.regex import RegexMixin as _RegexMixin
19
- from runtimepy.util import name_search
20
20
 
21
21
  # This determines types that are valid as keys.
22
22
  T = _TypeVar("T", int, bool)
@@ -11,7 +11,7 @@ from typing import Any, Optional, Union
11
11
 
12
12
  # third-party
13
13
  from vcorelib.dict.codec import JsonCodec
14
- from vcorelib.logging import LoggerType
14
+ from vcorelib.logging import ListLogger, LoggerType
15
15
  from vcorelib.target.resolver import TargetResolver
16
16
 
17
17
  # internal
@@ -39,7 +39,7 @@ from runtimepy.message.types import (
39
39
  T,
40
40
  TypedHandler,
41
41
  )
42
- from runtimepy.util import Identifier, ListLogger
42
+ from runtimepy.util import Identifier
43
43
 
44
44
 
45
45
  class JsonMessageInterface:
@@ -30,11 +30,14 @@ class ChannelEnvironmentMixin:
30
30
  return id(self.env)
31
31
 
32
32
  def register_task_metrics(
33
- self, metrics: PeriodicTaskMetrics, namespace: str = METRICS_NAME
33
+ self,
34
+ metrics: PeriodicTaskMetrics,
35
+ *names: str,
36
+ namespace: str = METRICS_NAME,
34
37
  ) -> None:
35
38
  """Register periodic task metrics."""
36
39
 
37
- with self.env.names_pushed(namespace):
40
+ with self.env.names_pushed(namespace, *names):
38
41
  self.env.channel(
39
42
  "dispatches",
40
43
  metrics.dispatches,
@@ -104,11 +107,14 @@ class ChannelEnvironmentMixin:
104
107
  )
105
108
 
106
109
  def register_connection_metrics(
107
- self, metrics: ConnectionMetrics, namespace: str = METRICS_NAME
110
+ self,
111
+ metrics: ConnectionMetrics,
112
+ *names: str,
113
+ namespace: str = METRICS_NAME,
108
114
  ) -> None:
109
115
  """Register connection metrics."""
110
116
 
111
- with self.env.names_pushed(namespace):
117
+ with self.env.names_pushed(namespace, *names):
112
118
  for name, direction, verb in [
113
119
  ("tx", metrics.tx, "transmitted"),
114
120
  ("rx", metrics.rx, "received"),
@@ -0,0 +1,110 @@
1
+ """
2
+ A module implementing a logger-mixin extension.
3
+ """
4
+
5
+ # built-in
6
+ from contextlib import AsyncExitStack
7
+ import io
8
+ import logging
9
+ from typing import Any, Iterable
10
+
11
+ # third-party
12
+ import aiofiles
13
+ from vcorelib.logging import LoggerMixin, LoggerType
14
+ from vcorelib.paths import Pathlike, normalize
15
+
16
+ # internal
17
+ from runtimepy.channel.environment import ChannelEnvironment
18
+ from runtimepy.enum.registry import RuntimeIntEnum
19
+
20
+
21
+ class LogLevel(RuntimeIntEnum):
22
+ """A runtime enumeration for log level."""
23
+
24
+ DEBUG = logging.DEBUG
25
+ INFO = logging.INFO
26
+ WARNING = logging.WARNING
27
+ ERROR = logging.ERROR
28
+ CRITICAL = logging.CRITICAL
29
+
30
+
31
+ LogLevellike = LogLevel | int | str
32
+
33
+
34
+ class LoggerMixinLevelControl(LoggerMixin):
35
+ """A logger mixin that exposes a runtime-controllable level."""
36
+
37
+ def _log_level_changed(self, _: int, new_value: int) -> None:
38
+ """Handle a change in log level."""
39
+
40
+ self.logger.setLevel(new_value)
41
+ self.logger.log(new_value, "Log level updated to %d.", new_value)
42
+
43
+ def setup_level_channel(
44
+ self,
45
+ env: ChannelEnvironment,
46
+ name: str = "log_level",
47
+ initial: str = "info",
48
+ description: str = "Text-log level filter for this environment.",
49
+ ) -> None:
50
+ """Add a commandable log-level channel to the environment."""
51
+
52
+ chan = env.int_channel(
53
+ name,
54
+ enum=LogLevel.register_enum(env.enums),
55
+ commandable=True,
56
+ description=description,
57
+ )
58
+
59
+ # Set up change handler.
60
+ chan[0].raw.register_callback(self._log_level_changed)
61
+
62
+ # Set the initial log level.
63
+ env.set(name, initial)
64
+
65
+ del chan
66
+
67
+
68
+ LogPaths = Iterable[tuple[LogLevellike, Pathlike]]
69
+
70
+
71
+ class LogCaptureMixin:
72
+ """A simple async file-reading interface."""
73
+
74
+ logger: LoggerType
75
+
76
+ # Open aiofiles handles.
77
+ streams: list[tuple[int, Any]]
78
+
79
+ ext_log_extra = {"external": True}
80
+
81
+ async def init_log_capture(
82
+ self, stack: AsyncExitStack, log_paths: LogPaths
83
+ ) -> None:
84
+ """Initialize this task with application information."""
85
+
86
+ self.streams = [
87
+ (
88
+ LogLevel.normalize(level),
89
+ await stack.enter_async_context(aiofiles.open(path, mode="r")),
90
+ )
91
+ for level, path in log_paths
92
+ if normalize(path).is_file()
93
+ ]
94
+
95
+ # Don't handle any kind of backhaul.
96
+ for stream in self.streams:
97
+ await stream[1].seek(0, io.SEEK_END)
98
+
99
+ def log_line(self, level: int, data: str) -> None:
100
+ """Log a line for output."""
101
+ self.logger.log(level, data, extra=self.ext_log_extra)
102
+
103
+ async def dispatch_log_capture(self) -> None:
104
+ """Get the next line from this log stream."""
105
+
106
+ for level, stream in self.streams:
107
+ line = (await stream.readline()).rstrip()
108
+ while line:
109
+ self.log_line(level, line)
110
+ line = (await stream.readline()).rstrip()
@@ -48,7 +48,9 @@ from runtimepy.subprocess.peer import RuntimepyPeer as _RuntimepyPeer
48
48
  from runtimepy.tui.mixin import CursesWindow, TuiMixin
49
49
 
50
50
  ServerTask = _Awaitable[None]
51
- RuntimeProcessTask = tuple[type[_RuntimepyPeer], str, _JsonObject, str]
51
+ RuntimeProcessTask = tuple[
52
+ type[_RuntimepyPeer], str, _JsonObject, str, Optional[str]
53
+ ]
52
54
 
53
55
 
54
56
  async def init_only(app: AppInfo) -> int:
@@ -226,9 +228,17 @@ class BaseConnectionArbiter(_NamespaceMixin, _LoggerMixin, TuiMixin):
226
228
  async def _start_processes(self, stack: _AsyncExitStack) -> None:
227
229
  """Start processes."""
228
230
 
229
- for name, (peer, name, config, import_str) in self._peers.items():
231
+ for name, (
232
+ peer,
233
+ name,
234
+ config,
235
+ import_str,
236
+ markdown,
237
+ ) in self._peers.items():
230
238
  self._runtime_peers[name] = await stack.enter_async_context(
231
- peer.running_program(name, config, import_str)
239
+ peer.running_program(
240
+ name, config, import_str, markdown=markdown
241
+ )
232
242
  )
233
243
  self.logger.info("Started process '%s'.", name)
234
244
 
@@ -17,6 +17,7 @@ from vcorelib.dict.env import dict_resolve_env_vars, list_resolve_env_vars
17
17
  from vcorelib.io import ARBITER as _ARBITER
18
18
  from vcorelib.io.types import JsonObject as _JsonObject
19
19
  from vcorelib.logging import LoggerMixin as _LoggerMixin
20
+ from vcorelib.names import import_str_and_item
20
21
  from vcorelib.paths import Pathlike as _Pathlike
21
22
  from vcorelib.paths import find_file
22
23
  from vcorelib.paths import normalize as _normalize
@@ -29,7 +30,6 @@ from runtimepy.net.arbiter.imports import (
29
30
  ImportConnectionArbiter as _ImportConnectionArbiter,
30
31
  )
31
32
  from runtimepy.net.arbiter.imports.util import get_apps
32
- from runtimepy.util import import_str_and_item
33
33
 
34
34
  ConfigObject = dict[str, _Any]
35
35
  ConfigBuilder = _Callable[[ConfigObject], None]
@@ -168,6 +168,7 @@ class ConfigConnectionArbiter(_ImportConnectionArbiter):
168
168
  kwargs = dict_resolve_env_vars(
169
169
  client.get("kwargs", {}), env=config.ports # type: ignore
170
170
  )
171
+ kwargs.setdefault("markdown", client.get("markdown"))
171
172
 
172
173
  assert await self.factory_client(
173
174
  factory,
@@ -201,6 +202,7 @@ class ConfigConnectionArbiter(_ImportConnectionArbiter):
201
202
  name,
202
203
  period_s=task["period_s"],
203
204
  average_depth=task["average_depth"],
205
+ markdown=task.get("markdown"),
204
206
  ), f"Couldn't register task '{name}' ({factory})!"
205
207
 
206
208
  # Register structs.
@@ -216,7 +218,9 @@ class ConfigConnectionArbiter(_ImportConnectionArbiter):
216
218
  name = process["name"]
217
219
  factory = process["factory"]
218
220
  assert self.factory_process(
219
- factory, name, process.get("config", {}), process["program"]
221
+ factory,
222
+ name,
223
+ process,
220
224
  ), f"Couldn't register process '{name}' ({factory})!"
221
225
 
222
226
  # Load initialization methods.
@@ -8,7 +8,7 @@ from importlib import import_module as _import_module
8
8
 
9
9
  # third-party
10
10
  from vcorelib.io.types import JsonObject as _JsonObject
11
- from vcorelib.names import to_snake
11
+ from vcorelib.names import import_str_and_item, to_snake
12
12
 
13
13
  # internal
14
14
  from runtimepy.net.arbiter.factory import (
@@ -23,7 +23,6 @@ from runtimepy.net.arbiter.factory.task import (
23
23
  from runtimepy.net.arbiter.info import RuntimeStruct as _RuntimeStruct
24
24
  from runtimepy.net.arbiter.task import TaskFactory as _TaskFactory
25
25
  from runtimepy.subprocess.peer import RuntimepyPeer as _RuntimepyPeer
26
- from runtimepy.util import import_str_and_item
27
26
 
28
27
 
29
28
  class ImportConnectionArbiter(
@@ -111,7 +110,7 @@ class ImportConnectionArbiter(
111
110
  return result
112
111
 
113
112
  def factory_process(
114
- self, factory: str, name: str, config: _JsonObject, program: str
113
+ self, factory: str, name: str, top_level: _JsonObject
115
114
  ) -> bool:
116
115
  """Register a runtime process."""
117
116
 
@@ -121,8 +120,9 @@ class ImportConnectionArbiter(
121
120
  self._peers[name] = (
122
121
  self._peer_factories[factory],
123
122
  name,
124
- config,
125
- program,
123
+ top_level.get("config", {}), # type: ignore
124
+ str(top_level["program"]),
125
+ top_level.get("markdown"),
126
126
  )
127
127
  result = True
128
128
 
@@ -5,10 +5,12 @@ Utility interfaces for arbiter runtime-import mechanisms.
5
5
  # built-in
6
6
  from importlib import import_module as _import_module
7
7
 
8
+ # third-party
9
+ from vcorelib.names import import_str_and_item
10
+
8
11
  # internal
9
12
  from runtimepy.net.arbiter.config.codec import ConfigApps
10
13
  from runtimepy.net.arbiter.info import ArbiterApps
11
- from runtimepy.util import import_str_and_item
12
14
 
13
15
 
14
16
  def get_apps(
@@ -13,9 +13,11 @@ from typing import Union as _Union
13
13
 
14
14
  # third-party
15
15
  from vcorelib.asyncio import log_exceptions as _log_exceptions
16
+ from vcorelib.io import MarkdownMixin
16
17
  from vcorelib.logging import LoggerType as _LoggerType
17
18
 
18
19
  # internal
20
+ from runtimepy import PKG_NAME
19
21
  from runtimepy.channel.environment import ChannelEnvironment
20
22
  from runtimepy.channel.environment.command.processor import (
21
23
  ChannelCommandProcessor,
@@ -30,7 +32,9 @@ from runtimepy.primitives.byte_order import DEFAULT_BYTE_ORDER, ByteOrder
30
32
  BinaryMessage = _Union[bytes, bytearray, memoryview]
31
33
 
32
34
 
33
- class Connection(LoggerMixinLevelControl, ChannelEnvironmentMixin, _ABC):
35
+ class Connection(
36
+ LoggerMixinLevelControl, ChannelEnvironmentMixin, MarkdownMixin, _ABC
37
+ ):
34
38
  """A connection interface."""
35
39
 
36
40
  uses_text_tx_queue = True
@@ -46,9 +50,11 @@ class Connection(LoggerMixinLevelControl, ChannelEnvironmentMixin, _ABC):
46
50
  logger: _LoggerType,
47
51
  env: ChannelEnvironment = None,
48
52
  add_metrics: bool = True,
53
+ markdown: str = None,
49
54
  ) -> None:
50
55
  """Initialize this connection."""
51
56
 
57
+ self.set_markdown(markdown=markdown, package=PKG_NAME)
52
58
  LoggerMixinLevelControl.__init__(self, logger=logger)
53
59
 
54
60
  # A queue for out-going text messages. Connections that don't use
@@ -9,6 +9,7 @@ from typing import Optional, TextIO, Union
9
9
 
10
10
  # third-party
11
11
  from vcorelib import DEFAULT_ENCODING
12
+ from vcorelib.logging import LoggerType
12
13
 
13
14
  HTTPMethodlike = Union[str, http.HTTPMethod]
14
15
  HEADER_LINESEP = "\r\n"
@@ -62,6 +63,10 @@ class HeadersMixin(ABC):
62
63
  def from_lines(self, lines: list[str]) -> None:
63
64
  """Update this request from line data."""
64
65
 
66
+ @abstractmethod
67
+ def log(self, logger: LoggerType, out: bool, **kwargs) -> None:
68
+ """Log information about this response header."""
69
+
65
70
  @abstractmethod
66
71
  def __str__(self) -> str:
67
72
  """Get this response as a string."""
@@ -55,7 +55,11 @@ class RequestHeader(HeadersMixin):
55
55
  HeadersMixin.__init__(self, lines[1:])
56
56
 
57
57
  def log(
58
- self, logger: LoggerType, out: bool, level: int = logging.DEBUG
58
+ self,
59
+ logger: LoggerType,
60
+ out: bool,
61
+ level: int = logging.DEBUG,
62
+ **_,
59
63
  ) -> None:
60
64
  """Log information about this request header."""
61
65
 
@@ -72,7 +72,7 @@ class ResponseHeader(HeadersMixin):
72
72
 
73
73
  return stream.getvalue()
74
74
 
75
- def log(self, logger: LoggerType, out: bool) -> None:
75
+ def log(self, logger: LoggerType, out: bool, **_) -> None:
76
76
  """Log information about this response header."""
77
77
 
78
78
  level = logging.INFO if (200 <= self.status <= 299) else logging.ERROR