runtimepy 5.12.2__tar.gz → 5.13.1__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 (318) hide show
  1. {runtimepy-5.12.2/runtimepy.egg-info → runtimepy-5.13.1}/PKG-INFO +6 -6
  2. {runtimepy-5.12.2 → runtimepy-5.13.1}/README.md +3 -3
  3. {runtimepy-5.12.2 → runtimepy-5.13.1}/pyproject.toml +1 -1
  4. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/__init__.py +3 -3
  5. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/__main__.py +1 -1
  6. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/app.py +1 -1
  7. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/commands/all.py +1 -1
  8. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/commands/server.py +0 -1
  9. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/css/main.css +1 -1
  10. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/entry.py +1 -1
  11. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/html/__init__.py +3 -1
  12. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/http/response.py +32 -0
  13. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/__init__.py +21 -11
  14. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/app/env/tab/html.py +1 -0
  15. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/app/env/widgets.py +2 -0
  16. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/html.py +16 -2
  17. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/markdown.py +16 -15
  18. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/tcp/http/__init__.py +29 -15
  19. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/requirements.txt +1 -1
  20. {runtimepy-5.12.2 → runtimepy-5.13.1/runtimepy.egg-info}/PKG-INFO +6 -6
  21. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy.egg-info/requires.txt +2 -2
  22. {runtimepy-5.12.2 → runtimepy-5.13.1}/setup.py +1 -1
  23. {runtimepy-5.12.2 → runtimepy-5.13.1}/LICENSE +0 -0
  24. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/channel/__init__.py +0 -0
  25. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/channel/environment/__init__.py +0 -0
  26. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/channel/environment/array.py +0 -0
  27. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/channel/environment/base.py +0 -0
  28. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/channel/environment/command/__init__.py +0 -0
  29. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/channel/environment/command/parser.py +0 -0
  30. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/channel/environment/command/processor.py +0 -0
  31. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/channel/environment/command/result.py +0 -0
  32. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/channel/environment/create.py +0 -0
  33. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/channel/environment/file.py +0 -0
  34. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/channel/environment/sample.py +0 -0
  35. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/channel/environment/telemetry.py +0 -0
  36. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/channel/event/__init__.py +0 -0
  37. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/channel/event/header.py +0 -0
  38. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/channel/registry.py +0 -0
  39. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/codec/__init__.py +0 -0
  40. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/codec/protocol/__init__.py +0 -0
  41. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/codec/protocol/base.py +0 -0
  42. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/codec/protocol/json.py +0 -0
  43. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/codec/system/__init__.py +0 -0
  44. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/commands/__init__.py +0 -0
  45. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/commands/arbiter.py +0 -0
  46. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/commands/common.py +0 -0
  47. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/commands/mtu.py +0 -0
  48. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/commands/task.py +0 -0
  49. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/commands/tftp.py +0 -0
  50. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/commands/tui.py +0 -0
  51. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/control/__init__.py +0 -0
  52. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/control/env/__init__.py +0 -0
  53. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/control/source.py +0 -0
  54. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/control/step.py +0 -0
  55. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/404.html +0 -0
  56. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/browser.yaml +0 -0
  57. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/css/bootstrap_extra.css +0 -0
  58. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/css/font.css +0 -0
  59. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/dummy_load.yaml +0 -0
  60. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/factories.yaml +0 -0
  61. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/favicon.ico +0 -0
  62. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/DataConnection.js +0 -0
  63. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/JsonConnection.js +0 -0
  64. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/audio.js +0 -0
  65. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/classes/App.js +0 -0
  66. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/classes/ChannelTable.js +0 -0
  67. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/classes/DataConnection.js +0 -0
  68. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/classes/JsonConnection.js +0 -0
  69. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/classes/OverlayManager.js +0 -0
  70. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/classes/Plot.js +0 -0
  71. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/classes/PlotDrawer.js +0 -0
  72. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/classes/PlotManager.js +0 -0
  73. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/classes/PlotModalManager.js +0 -0
  74. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/classes/PointBuffer.js +0 -0
  75. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/classes/PointManager.js +0 -0
  76. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/classes/TabFilter.js +0 -0
  77. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/classes/TabInterface.js +0 -0
  78. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/classes/UnitSystem.js +0 -0
  79. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/classes/WindowHashManager.js +0 -0
  80. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/classes/WorkerInterface.js +0 -0
  81. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/events.js +0 -0
  82. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/init.js +0 -0
  83. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/main.js +0 -0
  84. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/markdown_page.js +0 -0
  85. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/tab/env.js +0 -0
  86. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/tab/sound.js +0 -0
  87. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/third-party/webgl-debug.js +0 -0
  88. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/unused/pyodide.js +0 -0
  89. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/util.js +0 -0
  90. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/js/worker.js +0 -0
  91. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/md/Connection.md +0 -0
  92. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/md/PeriodicTask.md +0 -0
  93. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/md/RuntimeStruct.md +0 -0
  94. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/md/RuntimepyPeer.md +0 -0
  95. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/md/SinusoidTask.md +0 -0
  96. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/sample_telemetry.yaml +0 -0
  97. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/schemas/BitFields.yaml +0 -0
  98. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/schemas/Channel.yaml +0 -0
  99. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/schemas/ChannelCommand.yaml +0 -0
  100. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/schemas/ChannelRegistry.yaml +0 -0
  101. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/schemas/ClientConnectionConfig.yaml +0 -0
  102. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/schemas/ConnectionArbiterConfig.yaml +0 -0
  103. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/schemas/EnumRegistry.yaml +0 -0
  104. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/schemas/FindFile.yaml +0 -0
  105. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/schemas/PeerProcessConfig.yaml +0 -0
  106. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/schemas/RuntimeEnum.yaml +0 -0
  107. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/schemas/ServerConnectionConfig.yaml +0 -0
  108. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/schemas/StructConfig.yaml +0 -0
  109. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/schemas/TaskConfig.yaml +0 -0
  110. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/schemas/channel_controls.yaml +0 -0
  111. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/schemas/has_config.yaml +0 -0
  112. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/schemas/has_factory.yaml +0 -0
  113. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/schemas/has_markdown.yaml +0 -0
  114. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/schemas/has_name.yaml +0 -0
  115. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/schemas/has_request_flag.yaml +0 -0
  116. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/server.yaml +0 -0
  117. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/server_base.yaml +0 -0
  118. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/server_dev.yaml +0 -0
  119. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/css/bootstrap-icons.min.css +0 -0
  120. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/css/bootstrap.min.css +0 -0
  121. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/css/fonts/bootstrap-icons.woff +0 -0
  122. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/css/fonts/bootstrap-icons.woff2 +0 -0
  123. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/js/bootstrap.bundle.min.js +0 -0
  124. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/js/webglplot.umd.min.js +0 -0
  125. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/png/chip-circle-bootstrap/1024x1024.png +0 -0
  126. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/png/chip-circle-bootstrap/128x128.png +0 -0
  127. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/png/chip-circle-bootstrap/16x16.png +0 -0
  128. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/png/chip-circle-bootstrap/1920x1920.png +0 -0
  129. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/png/chip-circle-bootstrap/24x24.png +0 -0
  130. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/png/chip-circle-bootstrap/256x256.png +0 -0
  131. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/png/chip-circle-bootstrap/32x32.png +0 -0
  132. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/png/chip-circle-bootstrap/512x512.png +0 -0
  133. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/png/chip-circle-bootstrap/64x64.png +0 -0
  134. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/svg/chip-circle-bootstrap.svg +0 -0
  135. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/woff2/CascadiaCode-Bold.woff2 +0 -0
  136. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/woff2/CascadiaCode-BoldItalic.woff2 +0 -0
  137. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/woff2/CascadiaCode-Italic.woff2 +0 -0
  138. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/woff2/CascadiaCode-Regular.woff2 +0 -0
  139. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/woff2/CascadiaMono-Bold.woff2 +0 -0
  140. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/woff2/CascadiaMono-BoldItalic.woff2 +0 -0
  141. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/woff2/CascadiaMono-Italic.woff2 +0 -0
  142. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/woff2/CascadiaMono-Regular.woff2 +0 -0
  143. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/static/woff2/README.md +0 -0
  144. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/data/tftp_server.yaml +0 -0
  145. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/dev_requirements.txt +0 -0
  146. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/enum/__init__.py +0 -0
  147. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/enum/registry.py +0 -0
  148. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/enum/types.py +0 -0
  149. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/mapping.py +0 -0
  150. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/message/__init__.py +0 -0
  151. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/message/handlers.py +0 -0
  152. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/message/interface.py +0 -0
  153. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/message/types.py +0 -0
  154. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/metrics/__init__.py +0 -0
  155. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/metrics/channel.py +0 -0
  156. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/metrics/connection.py +0 -0
  157. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/metrics/task.py +0 -0
  158. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/mixins/__init__.py +0 -0
  159. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/mixins/async_command.py +0 -0
  160. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/mixins/enum.py +0 -0
  161. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/mixins/environment.py +0 -0
  162. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/mixins/finalize.py +0 -0
  163. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/mixins/logging.py +0 -0
  164. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/mixins/psutil.py +0 -0
  165. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/mixins/regex.py +0 -0
  166. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/mixins/trig.py +0 -0
  167. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/__init__.py +0 -0
  168. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/apps/__init__.py +0 -0
  169. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/arbiter/__init__.py +0 -0
  170. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/arbiter/base.py +0 -0
  171. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/arbiter/config/__init__.py +0 -0
  172. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/arbiter/config/codec.py +0 -0
  173. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/arbiter/config/util.py +0 -0
  174. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/arbiter/factory/__init__.py +0 -0
  175. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/arbiter/factory/connection.py +0 -0
  176. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/arbiter/factory/task.py +0 -0
  177. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/arbiter/housekeeping/__init__.py +0 -0
  178. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/arbiter/imports/__init__.py +0 -0
  179. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/arbiter/imports/util.py +0 -0
  180. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/arbiter/info.py +0 -0
  181. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/arbiter/result.py +0 -0
  182. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/arbiter/struct/__init__.py +0 -0
  183. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/arbiter/task.py +0 -0
  184. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/arbiter/tcp/__init__.py +0 -0
  185. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/arbiter/tcp/json.py +0 -0
  186. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/arbiter/udp.py +0 -0
  187. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/arbiter/websocket.py +0 -0
  188. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/backoff.py +0 -0
  189. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/connection.py +0 -0
  190. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/factories/__init__.py +0 -0
  191. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/html/arbiter.py +0 -0
  192. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/html/bootstrap/__init__.py +0 -0
  193. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/html/bootstrap/elements.py +0 -0
  194. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/html/bootstrap/tabs.py +0 -0
  195. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/http/__init__.py +0 -0
  196. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/http/common.py +0 -0
  197. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/http/header.py +0 -0
  198. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/http/request_target.py +0 -0
  199. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/http/state.py +0 -0
  200. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/http/version.py +0 -0
  201. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/manager.py +0 -0
  202. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/mixin.py +0 -0
  203. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/mtu.py +0 -0
  204. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/app/__init__.py +0 -0
  205. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/app/base.py +0 -0
  206. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/app/create.py +0 -0
  207. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/app/elements.py +0 -0
  208. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/app/env/__init__.py +0 -0
  209. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/app/env/modal.py +0 -0
  210. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/app/env/settings.py +0 -0
  211. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/app/env/tab/__init__.py +0 -0
  212. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/app/env/tab/base.py +0 -0
  213. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/app/env/tab/controls.py +0 -0
  214. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/app/env/tab/message.py +0 -0
  215. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/app/files.py +0 -0
  216. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/app/landing_page.py +0 -0
  217. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/app/placeholder.py +0 -0
  218. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/app/pyodide.py +0 -0
  219. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/app/sound.py +0 -0
  220. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/app/tab.py +0 -0
  221. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/json.py +0 -0
  222. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/struct/__init__.py +0 -0
  223. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/websocket/__init__.py +0 -0
  224. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/server/websocket/state.py +0 -0
  225. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/ssl.py +0 -0
  226. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/stream/__init__.py +0 -0
  227. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/stream/base.py +0 -0
  228. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/stream/json/__init__.py +0 -0
  229. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/stream/string.py +0 -0
  230. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/tcp/__init__.py +0 -0
  231. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/tcp/connection.py +0 -0
  232. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/tcp/create.py +0 -0
  233. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/tcp/protocol.py +0 -0
  234. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/tcp/scpi/__init__.py +0 -0
  235. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/tcp/telnet/__init__.py +0 -0
  236. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/tcp/telnet/codes.py +0 -0
  237. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/tcp/telnet/np_05b.py +0 -0
  238. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/udp/__init__.py +0 -0
  239. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/udp/connection.py +0 -0
  240. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/udp/create.py +0 -0
  241. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/udp/protocol.py +0 -0
  242. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/udp/queue.py +0 -0
  243. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/udp/tftp/__init__.py +0 -0
  244. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/udp/tftp/base.py +0 -0
  245. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/udp/tftp/endpoint.py +0 -0
  246. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/udp/tftp/enums.py +0 -0
  247. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/udp/tftp/io.py +0 -0
  248. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/util.py +0 -0
  249. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/websocket/__init__.py +0 -0
  250. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/net/websocket/connection.py +0 -0
  251. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/noise/__init__.py +0 -0
  252. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/__init__.py +0 -0
  253. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/array/__init__.py +0 -0
  254. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/base.py +0 -0
  255. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/bool.py +0 -0
  256. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/byte_order.py +0 -0
  257. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/evaluation.py +0 -0
  258. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/field/__init__.py +0 -0
  259. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/field/fields.py +0 -0
  260. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/field/manager/__init__.py +0 -0
  261. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/field/manager/base.py +0 -0
  262. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/float.py +0 -0
  263. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/int.py +0 -0
  264. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/scaling.py +0 -0
  265. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/serializable/__init__.py +0 -0
  266. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/serializable/base.py +0 -0
  267. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/serializable/fixed.py +0 -0
  268. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/serializable/framer.py +0 -0
  269. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/serializable/prefixed.py +0 -0
  270. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/string.py +0 -0
  271. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/types/__init__.py +0 -0
  272. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/types/base.py +0 -0
  273. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/types/bool.py +0 -0
  274. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/types/bounds.py +0 -0
  275. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/types/float.py +0 -0
  276. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/primitives/types/int.py +0 -0
  277. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/py.typed +0 -0
  278. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/registry/__init__.py +0 -0
  279. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/registry/bool.py +0 -0
  280. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/registry/item.py +0 -0
  281. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/registry/name.py +0 -0
  282. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/sample/__init__.py +0 -0
  283. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/sample/peer.py +0 -0
  284. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/sample/program.py +0 -0
  285. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/schemas.py +0 -0
  286. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/struct/__init__.py +0 -0
  287. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/subprocess/__init__.py +0 -0
  288. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/subprocess/interface.py +0 -0
  289. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/subprocess/peer.py +0 -0
  290. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/subprocess/program.py +0 -0
  291. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/subprocess/protocol.py +0 -0
  292. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/task/__init__.py +0 -0
  293. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/task/asynchronous.py +0 -0
  294. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/task/basic/__init__.py +0 -0
  295. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/task/basic/manager.py +0 -0
  296. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/task/basic/periodic.py +0 -0
  297. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/task/sample.py +0 -0
  298. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/task/trig/__init__.py +0 -0
  299. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/telemetry/__init__.py +0 -0
  300. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/telemetry/sample.py +0 -0
  301. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/tui/__init__.py +0 -0
  302. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/tui/channels/__init__.py +0 -0
  303. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/tui/cursor.py +0 -0
  304. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/tui/mixin.py +0 -0
  305. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/tui/mock.py +0 -0
  306. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/tui/task.py +0 -0
  307. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/ui/__init__.py +0 -0
  308. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/ui/controls.py +0 -0
  309. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy/util.py +0 -0
  310. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy.egg-info/SOURCES.txt +0 -0
  311. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy.egg-info/dependency_links.txt +0 -0
  312. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy.egg-info/entry_points.txt +0 -0
  313. {runtimepy-5.12.2 → runtimepy-5.13.1}/runtimepy.egg-info/top_level.txt +0 -0
  314. {runtimepy-5.12.2 → runtimepy-5.13.1}/setup.cfg +0 -0
  315. {runtimepy-5.12.2 → runtimepy-5.13.1}/tests/test_entry.py +0 -0
  316. {runtimepy-5.12.2 → runtimepy-5.13.1}/tests/test_mapping.py +0 -0
  317. {runtimepy-5.12.2 → runtimepy-5.13.1}/tests/test_resources.py +0 -0
  318. {runtimepy-5.12.2 → runtimepy-5.13.1}/tests/test_util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: runtimepy
3
- Version: 5.12.2
3
+ Version: 5.13.1
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: aiofiles
21
20
  Requires-Dist: psutil
21
+ Requires-Dist: aiofiles
22
+ Requires-Dist: svgen>=0.7.12
22
23
  Requires-Dist: websockets
23
24
  Requires-Dist: vcorelib>=3.5.1
24
- Requires-Dist: svgen>=0.7.4
25
25
  Provides-Extra: test
26
26
  Requires-Dist: pylint; extra == "test"
27
27
  Requires-Dist: flake8; extra == "test"
@@ -50,12 +50,12 @@ Dynamic: requires-python
50
50
  <!--
51
51
  =====================================
52
52
  generator=datazen
53
- version=3.2.1
54
- hash=c4f50a5547bbff6a73c98b12f4a8ee75
53
+ version=3.2.3
54
+ hash=69775d79c8c13f44e0ac000acdeb93e2
55
55
  =====================================
56
56
  -->
57
57
 
58
- # runtimepy ([5.12.2](https://pypi.org/project/runtimepy/))
58
+ # runtimepy ([5.13.1](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)
@@ -1,12 +1,12 @@
1
1
  <!--
2
2
  =====================================
3
3
  generator=datazen
4
- version=3.2.1
5
- hash=c4f50a5547bbff6a73c98b12f4a8ee75
4
+ version=3.2.3
5
+ hash=69775d79c8c13f44e0ac000acdeb93e2
6
6
  =====================================
7
7
  -->
8
8
 
9
- # runtimepy ([5.12.2](https://pypi.org/project/runtimepy/))
9
+ # runtimepy ([5.13.1](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.12.2"
7
+ version = "5.13.1"
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
- # version=3.2.1
4
- # hash=15077f6e9231129c803ebd9d9db1a5e1
3
+ # version=3.2.3
4
+ # hash=25280d90363095aa6b5717f2105ff685
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.12.2"
13
+ VERSION = "5.13.1"
14
14
 
15
15
  # runtimepy-specific content.
16
16
  METRICS_NAME = "metrics"
@@ -1,6 +1,6 @@
1
1
  # =====================================
2
2
  # generator=datazen
3
- # version=3.2.1
3
+ # version=3.2.3
4
4
  # hash=b28a8111bcc727e854c1f6474a3c4232
5
5
  # =====================================
6
6
  """
@@ -1,6 +1,6 @@
1
1
  # =====================================
2
2
  # generator=datazen
3
- # version=3.2.1
3
+ # version=3.2.3
4
4
  # hash=a4deafb4ebcc179d8d85f9376d22dc92
5
5
  # =====================================
6
6
 
@@ -1,6 +1,6 @@
1
1
  # =====================================
2
2
  # generator=datazen
3
- # version=3.2.1
3
+ # version=3.2.3
4
4
  # hash=1814b7f7fae3556a0dbeec37141e4182
5
5
  # =====================================
6
6
 
@@ -48,7 +48,6 @@ def get_kwargs(args: _Namespace, **kwargs) -> dict[str, Any]:
48
48
  new_kwargs: dict[str, Any] = {**kwargs}
49
49
 
50
50
  # Pass additional arguments through.
51
- print(args)
52
51
  for opt in PASSTHROUGH:
53
52
  value = getattr(args, opt, None)
54
53
  if value is not None:
@@ -52,6 +52,6 @@ body > :first-child {
52
52
  border-right: var(--bs-border-width) var(--bs-border-style) var(--bs-link-hover-color) !important;
53
53
  }
54
54
 
55
- canvas:focus {
55
+ :focus {
56
56
  outline: none;
57
57
  }
@@ -1,6 +1,6 @@
1
1
  # =====================================
2
2
  # generator=datazen
3
- # version=3.2.1
3
+ # version=3.2.3
4
4
  # hash=79c31d1280a6e97b5d326aecb758c597
5
5
  # =====================================
6
6
 
@@ -51,9 +51,10 @@ def create_app_shell(
51
51
  # Dark/light theme switch button.
52
52
  bootstrap_button(
53
53
  icon_str("lightbulb"),
54
- tooltip=" Toggle light/dark.",
54
+ tooltip="Toggle light/dark.",
55
55
  id="theme-button",
56
56
  parent=button_column,
57
+ title="change theme button",
57
58
  )
58
59
 
59
60
  return container, button_column
@@ -112,6 +113,7 @@ def full_markdown_page(
112
113
  icon_str("printer"),
113
114
  tooltip="Printer-friendly view.",
114
115
  id="print-button",
116
+ title="print-view button",
115
117
  parent=div(tag="a", href="?print=true", parent=button_column),
116
118
  )
117
119
 
@@ -6,8 +6,12 @@ A module implementing HTTP-response interfaces.
6
6
  import http
7
7
  from io import StringIO
8
8
  import logging
9
+ from pathlib import Path
10
+ from typing import AsyncIterator, cast
9
11
 
10
12
  # third-party
13
+ import aiofiles
14
+ import aiofiles.os
11
15
  from vcorelib.logging import LoggerType
12
16
 
13
17
  # internal
@@ -83,3 +87,31 @@ class ResponseHeader(HeadersMixin):
83
87
  self.status_line,
84
88
  self.headers,
85
89
  )
90
+
91
+
92
+ class AsyncResponse:
93
+ """
94
+ A class facilitating asynchronous server responses for e.g.
95
+ file-system files.
96
+ """
97
+
98
+ def __init__(self, path: Path, chunk_size: int = 1024) -> None:
99
+ """Initialize this instance."""
100
+
101
+ self.path = path
102
+ self.chunk_size = chunk_size
103
+
104
+ async def size(self) -> int:
105
+ """Get this response's size."""
106
+ return cast(int, await aiofiles.os.path.getsize(self.path))
107
+
108
+ async def process(self) -> AsyncIterator[bytes]:
109
+ """Yield chunks to write asynchronously."""
110
+
111
+ async with aiofiles.open(self.path, mode="rb") as path_fd:
112
+ while True:
113
+ data = await path_fd.read(self.chunk_size)
114
+ if data:
115
+ yield data
116
+ else:
117
+ break
@@ -21,11 +21,11 @@ from runtimepy.channel.environment.command import GLOBAL
21
21
  from runtimepy.net.html import full_markdown_page
22
22
  from runtimepy.net.http.header import RequestHeader
23
23
  from runtimepy.net.http.request_target import PathMaybeQuery
24
- from runtimepy.net.http.response import ResponseHeader
24
+ from runtimepy.net.http.response import AsyncResponse, ResponseHeader
25
25
  from runtimepy.net.server.html import HtmlApp, HtmlApps, get_html, html_handler
26
26
  from runtimepy.net.server.json import encode_json, json_handler
27
27
  from runtimepy.net.server.markdown import markdown_for_dir
28
- from runtimepy.net.tcp.http import HttpConnection
28
+ from runtimepy.net.tcp.http import HttpConnection, HttpResult
29
29
  from runtimepy.util import normalize_root, path_has_part, read_binary
30
30
 
31
31
  MIMETYPES_INIT = False
@@ -156,7 +156,9 @@ class RuntimepyServerConnection(HttpConnection):
156
156
 
157
157
  response["Content-Type"] = f"text/html; charset={DEFAULT_ENCODING}"
158
158
 
159
- return document.encode_str().encode()
159
+ with StringIO() as stream:
160
+ document.render(stream)
161
+ return stream.getvalue().encode()
160
162
 
161
163
  async def render_markdown_file(
162
164
  self,
@@ -173,20 +175,20 @@ class RuntimepyServerConnection(HttpConnection):
173
175
 
174
176
  async def try_file(
175
177
  self, path: PathMaybeQuery, response: ResponseHeader
176
- ) -> Optional[bytes]:
178
+ ) -> HttpResult:
177
179
  """Try serving this path as a file directly from the file-system."""
178
180
 
179
- result = None
181
+ result: HttpResult = None
180
182
 
181
183
  # Keep track of directories encountered.
182
- directories: list[Path] = []
184
+ directories: list[tuple[Path, Path]] = []
183
185
 
184
186
  # Build a list of all candidate files to check.
185
187
  candidates: list[Path] = []
186
188
  for search in self.paths:
187
189
  candidate = search.joinpath(path[0][1:])
188
190
  if candidate.is_dir():
189
- directories.append(candidate)
191
+ directories.append((candidate, search))
190
192
  candidates.append(candidate.joinpath("index.html"))
191
193
  else:
192
194
  candidates.append(candidate)
@@ -206,6 +208,13 @@ class RuntimepyServerConnection(HttpConnection):
206
208
 
207
209
  # Set MIME type if it can be determined.
208
210
  if mime:
211
+ # webhint suggestion
212
+ if (
213
+ mime.startswith("text")
214
+ and DEFAULT_ENCODING not in mime
215
+ ):
216
+ mime += f"; charset={DEFAULT_ENCODING}"
217
+
209
218
  response["Content-Type"] = mime
210
219
 
211
220
  # We don't handle this yet.
@@ -214,14 +223,15 @@ class RuntimepyServerConnection(HttpConnection):
214
223
  self.logger.info("Serving '%s' (MIME: %s)", candidate, mime)
215
224
 
216
225
  # Return the file data.
217
- result = await read_binary(candidate)
226
+ result = AsyncResponse(candidate)
218
227
  break
219
228
 
220
229
  # Handle a directory as a last resort.
221
230
  if not result and directories:
231
+ candidate, search = directories[0]
222
232
  result = self.render_markdown(
223
233
  markdown_for_dir(
224
- directories[0], {"applications": self.apps.keys()}
234
+ candidate, search, {"applications": self.apps.keys()}
225
235
  ),
226
236
  response,
227
237
  path[1],
@@ -259,7 +269,7 @@ class RuntimepyServerConnection(HttpConnection):
259
269
  response: ResponseHeader,
260
270
  request: RequestHeader,
261
271
  request_data: Optional[bytes],
262
- ) -> Optional[bytes]:
272
+ ) -> HttpResult:
263
273
  """Handle POST requests."""
264
274
 
265
275
  request.log(self.logger, False, level=logging.INFO)
@@ -281,7 +291,7 @@ class RuntimepyServerConnection(HttpConnection):
281
291
  response: ResponseHeader,
282
292
  request: RequestHeader,
283
293
  request_data: Optional[bytes],
284
- ) -> Optional[bytes]:
294
+ ) -> HttpResult:
285
295
  """Handle GET requests."""
286
296
 
287
297
  request.log(self.logger, False, level=logging.INFO)
@@ -226,6 +226,7 @@ class ChannelEnvironmentTabHtml(ChannelEnvironmentTabControls):
226
226
  vert_container = flex(
227
227
  parent=container,
228
228
  kind="column",
229
+ tag="form",
229
230
  )
230
231
  vert_container.add_class("channel-column", "collapse", "show")
231
232
 
@@ -110,6 +110,7 @@ def channel_table_header(
110
110
  tooltip="Clear plotted channels.",
111
111
  icon="x-lg",
112
112
  id="clear-plotted-channels",
113
+ title="button for clearing plotted channels",
113
114
  ).add_class("pb-2")
114
115
 
115
116
  input_box(
@@ -124,6 +125,7 @@ def channel_table_header(
124
125
  icon="trash",
125
126
  tooltip="Clear all plot points.",
126
127
  id="clear-plotted-points",
128
+ title="button for clearing plot point data",
127
129
  ).add_class("pb-2")
128
130
 
129
131
  cell = flex(tag="th", parent=ctl_row)
@@ -6,6 +6,7 @@ A module implementing HTML interfaces for web applications.
6
6
  from typing import Awaitable, Callable, Optional, TextIO
7
7
 
8
8
  # third-party
9
+ from svgen.element import Element
9
10
  from svgen.element.html import Html
10
11
  from vcorelib import DEFAULT_ENCODING
11
12
 
@@ -20,10 +21,23 @@ HtmlApp = Callable[
20
21
  HtmlApps = dict[str, HtmlApp]
21
22
 
22
23
 
23
- def get_html() -> Html:
24
+ def get_html(
25
+ title: str = HttpConnection.identity,
26
+ cache_control: str = "public",
27
+ **kwargs,
28
+ ) -> Html:
24
29
  """Get a default HTML document."""
25
30
 
26
- return Html(HttpConnection.identity)
31
+ elem = Html(title, **kwargs)
32
+
33
+ elem.children.append(
34
+ Element(
35
+ tag="meta",
36
+ attrib={"http-equiv": "Cache-Control", "content": cache_control},
37
+ )
38
+ )
39
+
40
+ return elem
27
41
 
28
42
 
29
43
  async def html_handler(
@@ -11,14 +11,11 @@ from typing import Iterable, cast
11
11
  from vcorelib.io.file_writer import IndentedFileWriter
12
12
  from vcorelib.paths import rel
13
13
 
14
- LOGO_MARKDOWN = (
15
- "[![logo](https://libre-embedded.com/static/"
16
- "png/chip-circle-bootstrap/128x128.png)](https://libre-embedded.com)"
17
- )
14
+ LOGO_MARKDOWN = "[![logo](/static/png/chip-circle-bootstrap/128x128.png)](/)"
18
15
 
19
16
 
20
17
  def markdown_for_dir(
21
- path: Path, extra_links: dict[str, Iterable[str]] = None
18
+ path: Path, base: Path, extra_links: dict[str, Iterable[str]] = None
22
19
  ) -> str:
23
20
  """Get markdown data for a directory."""
24
21
 
@@ -29,24 +26,28 @@ def markdown_for_dir(
29
26
 
30
27
  if extra_links:
31
28
  for category, apps in extra_links.items():
32
- writer.write(f"## {category}")
33
- with writer.padding():
34
- for app in apps:
35
- writer.write(f"* [{app}]({app})")
36
-
37
- writer.write(f"## `{path}`")
29
+ if apps:
30
+ writer.write(f"## {category}")
31
+ with writer.padding():
32
+ for app in apps:
33
+ writer.write(f"* [{app}]({app})")
34
+
35
+ curr_dir = rel(path, base=base)
36
+ writer.write(f"## `{curr_dir}`")
38
37
  writer.empty()
39
38
 
40
- writer.write("* [..](..)")
39
+ # Link to go up a directory.
40
+ if curr_dir != Path():
41
+ writer.write(f"* [..](/{curr_dir.parent})")
41
42
 
42
43
  for item in path.iterdir():
43
- curr = rel(item, base=path)
44
+ curr = rel(item, base=base)
44
45
 
45
- name = f"`{curr}`"
46
+ name = f"`{curr.name}`"
46
47
  if item.is_dir():
47
48
  name = f"**{name}**"
48
49
 
49
- writer.write(f"* [{name}]({curr})")
50
+ writer.write(f"* [{name}](/{curr})")
50
51
 
51
52
  result: str = cast(StringIO, writer.stream).getvalue()
52
53
 
@@ -16,22 +16,24 @@ from vcorelib import DEFAULT_ENCODING
16
16
  from runtimepy import PKG_NAME, VERSION
17
17
  from runtimepy.net.http import HttpMessageProcessor
18
18
  from runtimepy.net.http.header import RequestHeader
19
- from runtimepy.net.http.response import ResponseHeader
19
+ from runtimepy.net.http.response import AsyncResponse, ResponseHeader
20
20
  from runtimepy.net.tcp.connection import TcpConnection as _TcpConnection
21
21
 
22
+ HttpResult = Optional[bytes | AsyncResponse]
23
+
22
24
  #
23
25
  # async def handler(
24
26
  # response: ResponseHeader,
25
27
  # request: RequestHeader,
26
28
  # request_data: Optional[bytes],
27
- # ) -> Optional[bytes]:
29
+ # ) -> HttpResult:
28
30
  # """Sample handler."""
29
31
  #
30
32
  HttpRequestHandler = Callable[
31
33
  [ResponseHeader, RequestHeader, Optional[bytes]],
32
- Awaitable[Optional[bytes]],
34
+ Awaitable[HttpResult],
33
35
  ]
34
- HttpResponse = Tuple[ResponseHeader, Optional[bytes]]
36
+ HttpResponse = Tuple[ResponseHeader, HttpResult]
35
37
 
36
38
  HttpRequestHandlers = dict[http.HTTPMethod, HttpRequestHandler]
37
39
 
@@ -89,7 +91,7 @@ class HttpConnection(_TcpConnection):
89
91
  response: ResponseHeader,
90
92
  request: RequestHeader,
91
93
  request_data: Optional[bytes],
92
- ) -> Optional[bytes]:
94
+ ) -> HttpResult:
93
95
  """Sample handler."""
94
96
 
95
97
  async def post_handler(
@@ -97,7 +99,7 @@ class HttpConnection(_TcpConnection):
97
99
  response: ResponseHeader,
98
100
  request: RequestHeader,
99
101
  request_data: Optional[bytes],
100
- ) -> Optional[bytes]:
102
+ ) -> HttpResult:
101
103
  """Sample handler."""
102
104
 
103
105
  async def _process_request(
@@ -105,7 +107,7 @@ class HttpConnection(_TcpConnection):
105
107
  response: ResponseHeader,
106
108
  request_header: RequestHeader,
107
109
  request_data: Optional[bytes] = None,
108
- ) -> Optional[bytes]:
110
+ ) -> HttpResult:
109
111
  """Process an individual request."""
110
112
 
111
113
  result = None
@@ -124,7 +126,11 @@ class HttpConnection(_TcpConnection):
124
126
  )
125
127
 
126
128
  # Set boilerplate header data.
127
- response["server"] = self.identity
129
+
130
+ # webhint suggestions
131
+ # response["server"] = self.identity
132
+ response["server"] = PKG_NAME
133
+ response["X-Content-Type-Options"] = "nosniff"
128
134
 
129
135
  return result
130
136
 
@@ -137,7 +143,7 @@ class HttpConnection(_TcpConnection):
137
143
  # Set boilerplate header data.
138
144
  request["user-agent"] = self.identity
139
145
 
140
- self._send(request, data)
146
+ await self._send(request, data)
141
147
  self.expecting_response = True
142
148
  result = await self.responses.get()
143
149
  self.expecting_response = False
@@ -153,21 +159,29 @@ class HttpConnection(_TcpConnection):
153
159
  """
154
160
  return to_json(await self.request(request, data))
155
161
 
156
- def _send(
162
+ async def _send(
157
163
  self,
158
164
  header: Union[ResponseHeader, RequestHeader],
159
- data: Optional[bytes] = None,
165
+ data: HttpResult = None,
160
166
  ) -> None:
161
167
  """Send a request or response to a request."""
162
168
 
163
169
  # Set content length.
164
170
  header["content-length"] = "0"
165
- if data:
171
+
172
+ if isinstance(data, AsyncResponse):
173
+ header["content-length"] = str(await data.size())
174
+ elif data is not None:
166
175
  header["content-length"] = str(len(data))
167
176
 
168
177
  self.send_binary(bytes(header))
169
- if data:
170
- self.send_binary(data)
178
+
179
+ if data is not None:
180
+ if isinstance(data, AsyncResponse):
181
+ async for chunk in data.process():
182
+ self.send_binary(chunk)
183
+ else:
184
+ self.send_binary(data)
171
185
 
172
186
  header.log(self.logger, True)
173
187
 
@@ -183,7 +197,7 @@ class HttpConnection(_TcpConnection):
183
197
  if not self.expecting_response:
184
198
  # Process request.
185
199
  response = ResponseHeader()
186
- self._send(
200
+ await self._send(
187
201
  response,
188
202
  await self._process_request(
189
203
  response, cast(RequestHeader, header), payload
@@ -1,6 +1,6 @@
1
1
  aiofiles
2
2
  vcorelib>=3.5.1
3
- svgen>=0.7.4
3
+ svgen>=0.7.12
4
4
  websockets
5
5
  psutil
6
6
  windows-curses; sys_platform == 'win32' and python_version < '3.12'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: runtimepy
3
- Version: 5.12.2
3
+ Version: 5.13.1
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: aiofiles
21
20
  Requires-Dist: psutil
21
+ Requires-Dist: aiofiles
22
+ Requires-Dist: svgen>=0.7.12
22
23
  Requires-Dist: websockets
23
24
  Requires-Dist: vcorelib>=3.5.1
24
- Requires-Dist: svgen>=0.7.4
25
25
  Provides-Extra: test
26
26
  Requires-Dist: pylint; extra == "test"
27
27
  Requires-Dist: flake8; extra == "test"
@@ -50,12 +50,12 @@ Dynamic: requires-python
50
50
  <!--
51
51
  =====================================
52
52
  generator=datazen
53
- version=3.2.1
54
- hash=c4f50a5547bbff6a73c98b12f4a8ee75
53
+ version=3.2.3
54
+ hash=69775d79c8c13f44e0ac000acdeb93e2
55
55
  =====================================
56
56
  -->
57
57
 
58
- # runtimepy ([5.12.2](https://pypi.org/project/runtimepy/))
58
+ # runtimepy ([5.13.1](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)
@@ -1,8 +1,8 @@
1
- aiofiles
2
1
  psutil
2
+ aiofiles
3
+ svgen>=0.7.12
3
4
  websockets
4
5
  vcorelib>=3.5.1
5
- svgen>=0.7.4
6
6
 
7
7
  [test]
8
8
  pylint
@@ -1,6 +1,6 @@
1
1
  # =====================================
2
2
  # generator=datazen
3
- # version=3.2.1
3
+ # version=3.2.3
4
4
  # hash=23791ff25e92caf639fdcfe48ce010bf
5
5
  # =====================================
6
6
 
File without changes