runtimepy 5.15.2__py3-none-any.whl → 5.15.4__py3-none-any.whl

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.
runtimepy/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
1
  # =====================================
2
2
  # generator=datazen
3
3
  # version=3.2.3
4
- # hash=839ec3c3fa52de16f775789c0d38bf3e
4
+ # hash=b0f0463a508c9a1312a071f5c0b06f3b
5
5
  # =====================================
6
6
 
7
7
  """
@@ -10,7 +10,7 @@ Useful defaults and other package metadata.
10
10
 
11
11
  DESCRIPTION = "A framework for implementing Python services."
12
12
  PKG_NAME = "runtimepy"
13
- VERSION = "5.15.2"
13
+ VERSION = "5.15.4"
14
14
 
15
15
  # runtimepy-specific content.
16
16
  METRICS_NAME = "metrics"
@@ -54,6 +54,7 @@ class BaseChannelEnvironment(_NamespaceMixin, FinalizeMixin):
54
54
  fields: _Iterable[_BitFields] = None,
55
55
  namespace: Namespace = None,
56
56
  namespace_delim: str = DEFAULT_DELIM,
57
+ views: dict[str, str] = None,
57
58
  ) -> None:
58
59
  """Initialize this channel environment."""
59
60
 
@@ -105,6 +106,10 @@ class BaseChannelEnvironment(_NamespaceMixin, FinalizeMixin):
105
106
  if values is not None:
106
107
  self.apply(values)
107
108
 
109
+ if not views:
110
+ views = {}
111
+ self.views = views
112
+
108
113
  def __setitem__(self, key: _RegistryKey, value: ChannelValue) -> None:
109
114
  """Mapping-set interface."""
110
115
  return self.set(key, value)
@@ -12,7 +12,9 @@ from typing import Any, Iterator, Optional, cast
12
12
 
13
13
  # third-party
14
14
  from vcorelib import DEFAULT_ENCODING
15
+ from vcorelib.dict import GenericStrDict
15
16
  from vcorelib.io import ARBITER, JsonObject
17
+ from vcorelib.io.bus import BUS
16
18
  from vcorelib.logging import DEFAULT_TIME_FORMAT, LoggerMixin
17
19
  from vcorelib.math import default_time_ns, nano_str
18
20
  from vcorelib.names import name_search
@@ -25,6 +27,7 @@ from runtimepy.channel.environment.command.processor import (
25
27
  CommandHook,
26
28
  EnvironmentMap,
27
29
  )
30
+ from runtimepy.channel.environment.command.result import CommandResult
28
31
  from runtimepy.channel.registry import ParsedEvent
29
32
  from runtimepy.mapping import DEFAULT_PATTERN
30
33
 
@@ -243,6 +246,38 @@ GLOBAL = GlobalEnvironment()
243
246
  ENVIRONMENTS = GLOBAL
244
247
 
245
248
 
249
+ def global_command(env: str, value: str) -> Optional[CommandResult]:
250
+ """Handle a global command."""
251
+
252
+ result = None
253
+ if env in GLOBAL:
254
+ result = GLOBAL[env].command(value)
255
+ else:
256
+ GLOBAL.logger.error(
257
+ "Couldn't run command env='%s' value='%s'.", env, value
258
+ )
259
+ return result
260
+
261
+
262
+ def global_commands(*cmds: tuple[str, str]) -> None:
263
+ """Handle a global command."""
264
+ for env, value in cmds:
265
+ global_command(env, value)
266
+
267
+
268
+ async def global_command_bus(payload: GenericStrDict) -> None:
269
+ """Handle a bus message."""
270
+
271
+ if "env" in payload and "value" in payload:
272
+ global_command(payload["env"], payload["value"])
273
+ elif "cmds" in payload:
274
+ global_commands(*payload["cmds"])
275
+
276
+
277
+ BUS.register_ro("command", global_command_bus)
278
+ BUS.register_ro("cmd", global_command_bus)
279
+
280
+
246
281
  def clear_env() -> None:
247
282
  """Reset the global environment mapping."""
248
283
  GLOBAL.clear()
@@ -42,6 +42,8 @@ ENUMS_FILE = f"{ENUMS_KEY}.json"
42
42
  VALUES_FILE = f"{VALUES_KEY}.json"
43
43
  FIELDS_FILE = f"{FIELDS_KEY}.json"
44
44
  NAMES_FILE = f"{NAMES_KEY}.json"
45
+ VIEWS_KEY = "views"
46
+ # VIEWS_FILE = f"{VIEWS_KEY}.json"
45
47
 
46
48
 
47
49
  class FileChannelEnvironment(_BaseChannelEnvironment):
@@ -64,6 +66,7 @@ class FileChannelEnvironment(_BaseChannelEnvironment):
64
66
  VALUES_KEY: _cast(
65
67
  _JsonObject, self.values(resolve_enum=resolve_enum)
66
68
  ),
69
+ VIEWS_KEY: _cast(_JsonObject, self.views),
67
70
  }
68
71
 
69
72
  def export(
@@ -143,6 +146,7 @@ class FileChannelEnvironment(_BaseChannelEnvironment):
143
146
  enums=enum_reg,
144
147
  values=_cast(_Optional[_ValueMap], data.get(VALUES_KEY)),
145
148
  fields=_fields_from_dict(data[FIELDS_KEY]),
149
+ views=_cast(dict[str, str], data.get(VIEWS_KEY, {})),
146
150
  )
147
151
 
148
152
  # Typically, externally loaded environments should be final at load
@@ -9,6 +9,9 @@ tasks:
9
9
  a: 1
10
10
  b: 2
11
11
  c: 3
12
+ views:
13
+ - [zero, "\\.0\\."]
14
+ - [one, "\\.1\\."]
12
15
  markdown: |
13
16
  # This is a Test
14
17
 
@@ -29,6 +32,9 @@ tasks:
29
32
  - name: wave3
30
33
  factory: sinusoid
31
34
  period_s: 0.03
35
+ config:
36
+ views:
37
+ - [trig, sin cos]
32
38
  markdown: |
33
39
  # Markdown for wave3
34
40
 
@@ -50,6 +56,10 @@ clients:
50
56
  defer: true
51
57
  kwargs:
52
58
  remote_addr: [localhost, "$udp_json"]
59
+ views:
60
+ - [metrics, metrics]
61
+ - [transmit, tx]
62
+ - [receive, rx]
53
63
  markdown: |
54
64
  # `udp_json_client`
55
65
 
@@ -107,3 +117,7 @@ processes:
107
117
  app: runtimepy.sample.program.run
108
118
 
109
119
  program: runtimepy.sample.program.SampleProgram
120
+
121
+ commands:
122
+ - [udp_json_client, "set log_level warning"]
123
+ - [proc1.peer, "set log_level warning"]
@@ -56,6 +56,10 @@ class ChannelTable {
56
56
 
57
57
  if (Number.isInteger(val)) {
58
58
  /* Handle integer formatting. */
59
+ } else if (typeof val == "boolean") {
60
+ /* Use glyphs for booleans. */
61
+ val = val ? '<i class="bi bi-circle-fill"></i>'
62
+ : '<i class="bi bi-circle"></i>';
59
63
  } else {
60
64
  /* Handle floating-point numbers. */
61
65
  let checkFloat = Number.parseFloat(val);
@@ -263,6 +263,19 @@ class TabInterface {
263
263
  this.updateChannelStyles(this.channelFilter.value);
264
264
  };
265
265
  }
266
+
267
+ /* Initialize channel view dropdown. */
268
+ let channelView = this.query("#filter-view");
269
+ if (channelView) {
270
+ channelView.onchange = () => {
271
+ if (!channelView.value || channelView.value == '-') {
272
+ this.channelFilter.value = "";
273
+ } else {
274
+ this.channelFilter.value = channelView.value;
275
+ }
276
+ this.updateChannelStyles(this.channelFilter.value);
277
+ };
278
+ }
266
279
  }
267
280
 
268
281
  setHandler(elem) {
runtimepy/data/js/init.js CHANGED
@@ -53,8 +53,10 @@ function isModifierKeyEvent(event) {
53
53
  }
54
54
 
55
55
  function ignoreFilterKeyEvent(event) {
56
- // home end pg up pg down delete f keys
57
- return isModifierKeyEvent(event) || event.key == "Tab";
56
+ return isModifierKeyEvent(event) || event.key == "Tab" ||
57
+ (event.key.startsWith("F") && event.key.length > 1) ||
58
+ event.key.startsWith("Del") || event.key == "Home" ||
59
+ event.key == "End" || event.key == "PageUp" || event.key == "PageDown";
58
60
  }
59
61
 
60
62
  function globalKeyEvent(event) {
@@ -3,6 +3,7 @@ includes:
3
3
  - has_factory.yaml
4
4
  - has_name.yaml
5
5
  - has_markdown.yaml
6
+ - has_views.yaml
6
7
 
7
8
  properties:
8
9
  defer:
@@ -26,6 +26,9 @@ properties:
26
26
  items:
27
27
  $ref: package://runtimepy/schemas/StructConfig.yaml
28
28
 
29
+ commands:
30
+ $ref: package://runtimepy/schemas/TwoTupleArray.yaml
31
+
29
32
  tasks:
30
33
  type: array
31
34
  items:
@@ -4,6 +4,7 @@ includes:
4
4
  - has_name.yaml
5
5
  - has_config.yaml
6
6
  - has_markdown.yaml
7
+ - has_views.yaml
7
8
 
8
9
  properties:
9
10
  program:
@@ -0,0 +1,9 @@
1
+ ---
2
+ type: array
3
+ items:
4
+ type: array
5
+ minItems: 2
6
+ maxItems: 2
7
+ items:
8
+ - type: string
9
+ - type: string
@@ -0,0 +1,4 @@
1
+ ---
2
+ properties:
3
+ views:
4
+ $ref: package://runtimepy/schemas/TwoTupleArray.yaml
@@ -26,6 +26,7 @@ from vcorelib.namespace import NamespaceMixin as _NamespaceMixin
26
26
  from runtimepy.channel.environment.command import (
27
27
  clear_env,
28
28
  env_json_data,
29
+ global_commands,
29
30
  register_env,
30
31
  )
31
32
  from runtimepy.net.arbiter.housekeeping import housekeeping
@@ -145,6 +146,9 @@ class BaseConnectionArbiter(_NamespaceMixin, _LoggerMixin, TuiMixin):
145
146
  # A copy of named port mappings (loaded via external config).
146
147
  self._ports: dict[str, int] = {}
147
148
 
149
+ self._commands: list[tuple[str, str]] = []
150
+ self._views: dict[str, dict[str, str]] = {}
151
+
148
152
  self._init()
149
153
 
150
154
  def _init(self) -> None:
@@ -153,6 +157,9 @@ class BaseConnectionArbiter(_NamespaceMixin, _LoggerMixin, TuiMixin):
153
157
  def _register_connection(self, connection: _Connection, name: str) -> None:
154
158
  """Perform connection registration."""
155
159
 
160
+ if name in self._views:
161
+ connection.env.views.update(self._views[name])
162
+ del self._views[name]
156
163
  self._connections[name] = connection
157
164
  self.manager.queue.put_nowait(connection)
158
165
  connection.logger.info("Registered as '%s'.", name)
@@ -162,6 +169,7 @@ class BaseConnectionArbiter(_NamespaceMixin, _LoggerMixin, TuiMixin):
162
169
  connection: _Union[_Connection, _Awaitable[_Connection]],
163
170
  *names: str,
164
171
  delim: str = None,
172
+ views: dict[str, str] = None,
165
173
  ) -> bool:
166
174
  """Attempt to register a connection object."""
167
175
 
@@ -170,6 +178,9 @@ class BaseConnectionArbiter(_NamespaceMixin, _LoggerMixin, TuiMixin):
170
178
  with self.names_pushed(*names):
171
179
  name = self.namespace(delim=delim)
172
180
 
181
+ if views:
182
+ self._views[name] = views
183
+
173
184
  if (
174
185
  name not in self._connections
175
186
  and name not in self._deferred_connections
@@ -318,6 +329,11 @@ class BaseConnectionArbiter(_NamespaceMixin, _LoggerMixin, TuiMixin):
318
329
 
319
330
  # Run initialization methods.
320
331
  result = await self._run_apps_list(self._inits, info)
332
+
333
+ # Run commands.
334
+ await _asyncio.sleep(0)
335
+ global_commands(*self._commands)
336
+
321
337
  if result == 0:
322
338
  # Get application methods.
323
339
  apps = self._apps
@@ -170,7 +170,6 @@ class ConfigConnectionArbiter(_ImportConnectionArbiter):
170
170
  kwargs = dict_resolve_env_vars(
171
171
  client.get("kwargs", {}), env=self._ports # type: ignore
172
172
  )
173
- kwargs.setdefault("markdown", client.get("markdown"))
174
173
 
175
174
  assert await self.factory_client(
176
175
  factory,
@@ -179,6 +178,8 @@ class ConfigConnectionArbiter(_ImportConnectionArbiter):
179
178
  defer=client["defer"],
180
179
  # Perform some known fixes for common keyword arguments.
181
180
  **fix_kwargs(kwargs),
181
+ views=client.get("views"),
182
+ markdown=client.get("markdown"),
182
183
  ), f"Couldn't register client '{name}' ({factory})!"
183
184
 
184
185
  # Register servers.
@@ -245,5 +246,8 @@ class ConfigConnectionArbiter(_ImportConnectionArbiter):
245
246
  assert "root" not in config.config, config.config
246
247
  config.config["root"] = root
247
248
 
249
+ # Register commands.
250
+ self._commands = config.commands
251
+
248
252
 
249
253
  ConfigConnectionArbiter.add_search_package(PKG_NAME)
@@ -71,6 +71,11 @@ class ConnectionArbiterConfig(_RuntimepyDictCodec):
71
71
 
72
72
  self.directory = _Path(str(data.get("directory", ".")))
73
73
 
74
+ self.commands: list[tuple[str, str]] = data.get( # type: ignore
75
+ "commands",
76
+ [],
77
+ )
78
+
74
79
  def asdict(self) -> _JsonObject:
75
80
  """Obtain a dictionary representing this instance."""
76
81
  return self.data
@@ -89,12 +89,17 @@ class FactoryConnectionArbiter(_BaseConnectionArbiter):
89
89
  if factory in self._conn_factories:
90
90
  factory_inst = self._conn_factories[factory]
91
91
 
92
+ views = kwargs.pop("views", {})
93
+
92
94
  conn = factory_inst.client(name, *args, **kwargs)
93
95
  if not defer:
94
96
  conn = await conn # type: ignore
95
97
 
96
98
  result = self.register_connection(
97
- conn, *self._conn_names[factory_inst], name
99
+ conn,
100
+ *self._conn_names[factory_inst],
101
+ name,
102
+ views=views,
98
103
  )
99
104
 
100
105
  return result
@@ -18,7 +18,7 @@ from vcorelib.paths import Pathlike, find_file, normalize
18
18
 
19
19
  # internal
20
20
  from runtimepy import DEFAULT_EXT, PKG_NAME
21
- from runtimepy.channel.environment.command import GLOBAL
21
+ from runtimepy.channel.environment.command import GLOBAL, global_command
22
22
  from runtimepy.net.html import full_markdown_page
23
23
  from runtimepy.net.http.header import RequestHeader
24
24
  from runtimepy.net.http.request_target import PathMaybeQuery
@@ -270,17 +270,22 @@ class RuntimepyServerConnection(HttpConnection):
270
270
  response_data["success"] = False
271
271
  response_data["message"] = "No command executed."
272
272
 
273
- if not args or args[0] not in GLOBAL:
273
+ def cmd_usage() -> None:
274
+ """Set usage information for the response."""
274
275
  response_data["usage"] = (
275
276
  "/<environment (arg0)>/<arg1>[/.../<argN>]"
276
277
  )
277
278
  response_data["environments"] = list(GLOBAL)
278
279
 
279
- # Run command.
280
+ if args:
281
+ result = global_command(args[0], " ".join(args[1:]))
282
+ if result is None:
283
+ cmd_usage()
284
+ else:
285
+ response_data["success"] = result.success
286
+ response_data["message"] = str(result)
280
287
  else:
281
- result = GLOBAL[args[0]].command(" ".join(args[1:]))
282
- response_data["success"] = result.success
283
- response_data["message"] = str(result)
288
+ cmd_usage()
284
289
 
285
290
  # Send response.
286
291
  encode_json(stream, response, response_data)
@@ -80,6 +80,21 @@ def enum_dropdown(
80
80
  TABLE_BUTTON_CLASSES = ("border-top-0", "border-bottom-0")
81
81
 
82
82
 
83
+ def views_dropdown(parent: Element, command: ChannelCommandProcessor) -> None:
84
+ """Dropdown menu for channel environment views."""
85
+
86
+ select = select_element(
87
+ parent=div(tag="th", parent=parent, class_str="p-0"),
88
+ id="filter-view",
89
+ title="Canonical channel filters.",
90
+ ).add_class("border-end-0", "w-100")
91
+ div(tag="option", value="", text="-", parent=select)
92
+ for text, value in command.env.views.items():
93
+ div(tag="option", value=value, text=text, parent=select)
94
+ if not command.env.views:
95
+ select.booleans.add("disabled")
96
+
97
+
83
98
  def channel_table_header(
84
99
  parent: Element, command: ChannelCommandProcessor
85
100
  ) -> None:
@@ -105,7 +120,7 @@ def channel_table_header(
105
120
  ).add_class(*TABLE_BUTTON_CLASSES)
106
121
 
107
122
  _, label, box = input_box(
108
- div(tag="th", parent=ctl_row, colspan="2", class_str="p-0"),
123
+ div(tag="th", parent=ctl_row, class_str="p-0 border-end-0"),
109
124
  description="Channel name filter.",
110
125
  pattern=".* ! @ $",
111
126
  label="filter",
@@ -114,17 +129,18 @@ def channel_table_header(
114
129
  spellcheck="false",
115
130
  )
116
131
  label.add_class("border-top-0", "border-bottom-0")
117
- box.add_class("border-top-0", "border-bottom-0")
132
+ box.add_class("border-top-0", "border-bottom-0", "border-end-0")
133
+
134
+ views_dropdown(ctl_row, command)
118
135
 
119
136
  cell = flex(
120
137
  parent=div(tag="th", parent=ctl_row, colspan="2", class_str="p-0")
121
138
  )
122
139
 
123
- # Add a selection menu for custom commands.
140
+ # Add a selection menu for custom commands. (need a data source for this)
124
141
  select = select_element(
125
142
  parent=cell, id="custom-commands", title="Custom command selector."
126
143
  )
127
- select.add_class("border-start-0")
128
144
 
129
145
  if command.custom_commands:
130
146
  for key in command.custom_commands:
@@ -45,6 +45,7 @@ class RuntimeStructBase(
45
45
  self.set_markdown(config=config, markdown=markdown, package=PKG_NAME)
46
46
  LoggerMixinLevelControl.__init__(self, logger=_getLogger(self.name))
47
47
  ChannelEnvironmentMixin.__init__(self)
48
+ self.env.views.update(config.get("views", {})) # type: ignore
48
49
  if self.log_level_channel:
49
50
  self.setup_level_channel(self.env)
50
51
  self.command = ChannelCommandProcessor(self.env, self.logger)
@@ -72,6 +72,7 @@ class PeriodicTask(
72
72
  self.metrics = metrics
73
73
 
74
74
  ChannelEnvironmentMixin.__init__(self, env=env)
75
+ self.env.views.update(self.config.get("views", {})) # type: ignore
75
76
  self.setup_level_channel(self.env)
76
77
  self.command = ChannelCommandProcessor(self.env, self.logger)
77
78
  self.register_task_metrics(self.metrics)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: runtimepy
3
- Version: 5.15.2
3
+ Version: 5.15.4
4
4
  Summary: A framework for implementing Python services.
5
5
  Home-page: https://github.com/libre-embedded/runtimepy
6
6
  Author: Libre Embedded
@@ -17,11 +17,11 @@ Classifier: Development Status :: 5 - Production/Stable
17
17
  Requires-Python: >=3.12
18
18
  Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
- Requires-Dist: websockets
20
+ Requires-Dist: psutil
21
+ Requires-Dist: svgen>=0.8.0
21
22
  Requires-Dist: aiofiles
23
+ Requires-Dist: websockets
22
24
  Requires-Dist: vcorelib>=3.6.3
23
- Requires-Dist: svgen>=0.8.0
24
- Requires-Dist: psutil
25
25
  Provides-Extra: test
26
26
  Requires-Dist: pylint; extra == "test"
27
27
  Requires-Dist: flake8; extra == "test"
@@ -51,11 +51,11 @@ Dynamic: requires-python
51
51
  =====================================
52
52
  generator=datazen
53
53
  version=3.2.3
54
- hash=f1c75c9b812e8ff29fdda46f58009aef
54
+ hash=99eea1986d2105483ebb2fe566128f5f
55
55
  =====================================
56
56
  -->
57
57
 
58
- # runtimepy ([5.15.2](https://pypi.org/project/runtimepy/))
58
+ # runtimepy ([5.15.4](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,4 +1,4 @@
1
- runtimepy/__init__.py,sha256=flvkr-56G2rUSF5MWiJFKowe_0LjNtJbpWzAdUU_B3M,391
1
+ runtimepy/__init__.py,sha256=Aiyyy3r4Wwnu9sBdfqT5dwlbFGVLbVwehYURBXxjA2g,391
2
2
  runtimepy/__main__.py,sha256=IKioH2xOtsXwrwb9zABDQEJvuAX--Lnh84TeSz0XSs0,332
3
3
  runtimepy/app.py,sha256=Er1ZKKrG9U0FV0gQg_GYF9xDb89HgYnVzS5SjxGa2Tg,970
4
4
  runtimepy/dev_requirements.txt,sha256=VZhW6bJ5YbwaoN4d_XxZFuN5BbDLaG7ngKrGnugVPRw,245
@@ -12,12 +12,12 @@ runtimepy/channel/__init__.py,sha256=bI1mfHmjUGrYcwePip2ddbMaGSkyQXQVfESL5dqXRdU
12
12
  runtimepy/channel/registry.py,sha256=AiRhSSnNbWCxwC-m8vP2fRaN1cfm5JjvlphQzkETf9w,4742
13
13
  runtimepy/channel/environment/__init__.py,sha256=Mmq4S4NCX9pKSH7XEmD04zm0YcRhrTc8mGb25dTULgw,5333
14
14
  runtimepy/channel/environment/array.py,sha256=f9cWaYsRXUw8qE629h6jQxbYKDpOwC2GLBo4QaMa1JM,3748
15
- runtimepy/channel/environment/base.py,sha256=uCQKCH6wNrKqYSX2PMDAbIFoCZh68Xt-Cr_daGG7eeI,14356
15
+ runtimepy/channel/environment/base.py,sha256=vZAPydAZ58qGf3HvUR6KjB5RzARHfigW1s01VZNcCAs,14467
16
16
  runtimepy/channel/environment/create.py,sha256=UVO_R5rM6xLjpAh3j3wwix-0V3uJMAno2tbBIV4boo8,5868
17
- runtimepy/channel/environment/file.py,sha256=PV05KZ3-CvftbKUM8acQmawOMeGGCcMrEESEBuymykg,6949
17
+ runtimepy/channel/environment/file.py,sha256=keAlt9CrGXHVbHimZV0gv0WZkKYBQ-c9YHgQtojceAk,7125
18
18
  runtimepy/channel/environment/sample.py,sha256=6926v0ZssvfeWX_C8MSbUfYjE4sr3jt0CLVSJ_2Cl3U,5316
19
19
  runtimepy/channel/environment/telemetry.py,sha256=3A7Xcp-4eHJWz_oR1SnI6rsl4o8wiSUaiMHrnK1IaQ8,5338
20
- runtimepy/channel/environment/command/__init__.py,sha256=mymqk5roA-7evUovXlD2dmWaprSzrPb_3ae6bA9oEZ0,8162
20
+ runtimepy/channel/environment/command/__init__.py,sha256=PRuIp29QYkTDHF95HL55G6ogQDkVbq0M3SnNre4JXpI,9150
21
21
  runtimepy/channel/environment/command/parser.py,sha256=cMOsEsXnfFlATiWTNSxlgvc_XoICsJlcZigFJlQ47tk,1804
22
22
  runtimepy/channel/environment/command/processor.py,sha256=NiiWRdwBHOFEisjqNOW5oawprxcpR25ONNABoZpELdg,7122
23
23
  runtimepy/channel/environment/command/result.py,sha256=Ko5lK4d04Z266WuCi2sHQItbUHJFYv7qUdrDi-OVKOU,624
@@ -45,7 +45,7 @@ runtimepy/control/env/__init__.py,sha256=RHJqysY7Pv4VDs2SGk0X-qc5xp_SrQ_oxb5Deug
45
45
  runtimepy/data/404.md,sha256=_yzjvp2GeMc5OBvZX2zDbX-Ns6T7HCO9esRbS5PmkXU,397
46
46
  runtimepy/data/base.yaml,sha256=PEsvcMV1qFb1Gr6Cx2SgmR6ScfPyuu3yTdnvSBTVSdA,453
47
47
  runtimepy/data/browser.yaml,sha256=oc5KEV1C1uAJ4MkhNo4hyVVfJtZvHelRNqzNvD313Ow,79
48
- runtimepy/data/dummy_load.yaml,sha256=oAuccgvM3lDoN5RZBo4UECiegxzOgpllBfXXwZ5odCw,2071
48
+ runtimepy/data/dummy_load.yaml,sha256=pVX29qClBJ4NzE2q7fVF3NCVpts6oaxvH2owmdtdohU,2373
49
49
  runtimepy/data/factories.yaml,sha256=CdpnjK2glj8HewI2tFSNvCSUdcNPeVD_tFbGy2QBSQg,1952
50
50
  runtimepy/data/favicon.ico,sha256=boxAGaHbUjMFrOO2TZpsO0nIRC-LUgwHVQYOiG1YQnM,362870
51
51
  runtimepy/data/sample_telemetry.yaml,sha256=OpdFurkvtWJGaNl9LMlU2rKo15AaVVr-U_hoZfsbp-Y,695
@@ -60,14 +60,14 @@ runtimepy/data/js/DataConnection.js,sha256=DnX8FMehjJXqmI62UMYXSvl_XdfQMzq3XUDFb
60
60
  runtimepy/data/js/JsonConnection.js,sha256=rclZrbmWc_zSs6I_JhOgxnVPFIyPMo5WdjAe8alyZ3o,2729
61
61
  runtimepy/data/js/audio.js,sha256=bLkBqbeHMiGGidfL3iXjmVoF9seK-ZeZ3kwgOrcpgk4,1092
62
62
  runtimepy/data/js/events.js,sha256=rgz3Q_8J6sfU_7Sa7fG1mZD0pQ4S3vwN2mqcvQfePkM,554
63
- runtimepy/data/js/init.js,sha256=6RhwGRl_DBjMpztms2JOQiQlvdizcLeaiETNEh31KyU,1992
63
+ runtimepy/data/js/init.js,sha256=LSZQKlgcIWmq4ue4kD1okRnN1qaVv0RalxFnqRiKWzI,2160
64
64
  runtimepy/data/js/main.js,sha256=nYIQ6O76EWqlzwX7oEwPXqC-LCUFCZYDADK9QbYRDKk,404
65
65
  runtimepy/data/js/markdown_page.js,sha256=R7Z2CwCk0dXED_4lwvDMXRNNB9ki9RvfwEKLPSwNWec,982
66
66
  runtimepy/data/js/sample.js,sha256=-ezzcH-U4hchWYgE2mMzO9lUdkmNDA_OojJRzA17AGU,88
67
67
  runtimepy/data/js/util.js,sha256=Xc8pHUiFDBDvIqTamWrCYUOpF7iR9VNvPDCSCQAfLDA,1424
68
68
  runtimepy/data/js/worker.js,sha256=V9deGAynjvUr1D-WGi3wUW8rxoaNLvBvayMoLFZk3w0,2444
69
69
  runtimepy/data/js/classes/App.js,sha256=t3XVC7zSi8L_sMJ4KP-lyWyuD4cysCKkptN-lgjewN8,5159
70
- runtimepy/data/js/classes/ChannelTable.js,sha256=v6CqDdJrxhbDZcp9c1k7a9cy1uIHfb_LsTmCfY8lvPM,2593
70
+ runtimepy/data/js/classes/ChannelTable.js,sha256=djnUVmZyG6NDMLBKol8lN1tjfLd7pnhMVR1MyYXSnL4,2792
71
71
  runtimepy/data/js/classes/DataConnection.js,sha256=DnX8FMehjJXqmI62UMYXSvl_XdfQMzq3XUDFbLu2GgI,98
72
72
  runtimepy/data/js/classes/JsonConnection.js,sha256=vgQ3bGvVU5dNXn_uwvH7HjOQm0PwUSx0239Vfi7h1vE,2858
73
73
  runtimepy/data/js/classes/OverlayManager.js,sha256=-eH8NtJi8doBUB2Czqand4cWuQlddo1p1wVUfjVx9w0,3362
@@ -78,7 +78,7 @@ runtimepy/data/js/classes/PlotModalManager.js,sha256=lEbACLC5VzV-aSAb7G-WacmLLf_
78
78
  runtimepy/data/js/classes/PointBuffer.js,sha256=iVtq_q5gBaV9IVX55pHVjQdMJ4phJ6QTdAiM7EZrLRA,5061
79
79
  runtimepy/data/js/classes/PointManager.js,sha256=0lr2AReLdDNrY47UuOjjCRDPMiSRsOVggFHDPf8V-6Y,460
80
80
  runtimepy/data/js/classes/TabFilter.js,sha256=xajU1ZzVI0jFGhaHkKFX4-d2n2KlxiTC4it3N53-KxM,2115
81
- runtimepy/data/js/classes/TabInterface.js,sha256=xBBPX9UqMXvo6yguaJ5p3-Za1lLj3FAMLQk5rx4azZ8,14864
81
+ runtimepy/data/js/classes/TabInterface.js,sha256=SXUSbhJyyLRWAPzbfKvn4IBMdk6fOgQcz4-DXh0JmR4,15280
82
82
  runtimepy/data/js/classes/UnitSystem.js,sha256=ys4OMabq47k_VvJpRItm82U0IequDvx3ysRJOQzDf94,906
83
83
  runtimepy/data/js/classes/WindowHashManager.js,sha256=aR8zs1gUq9vkStLjyQj4rssx4dujLdDcoWNs91ViV44,7461
84
84
  runtimepy/data/js/classes/WorkerInterface.js,sha256=5jn5JX3cx-1oBVBpZ6X6E5x6uk5vmKQ98EMBoRAaqxk,402
@@ -95,21 +95,23 @@ runtimepy/data/schemas/BitFields.yaml,sha256=iE_3y30CgcpxvzwoC96BDhwbu2PZC-Lqu5C
95
95
  runtimepy/data/schemas/Channel.yaml,sha256=9OQ3mOtPOlcWugvObpWKoAdFW0WvR9mSEzfdDYNf3fc,471
96
96
  runtimepy/data/schemas/ChannelCommand.yaml,sha256=h7-n5WjNwWgteZ8U5YpaBRncR_Uiqaa_wVfuTWQFrTY,257
97
97
  runtimepy/data/schemas/ChannelRegistry.yaml,sha256=f51YngVC8zDM3HwRMicKBOyoqjJ9EWsx3GWD0EkHCZk,136
98
- runtimepy/data/schemas/ClientConnectionConfig.yaml,sha256=XUWkOiCOw175harOsDRV3TXJja-EAKnipYDQFf_XC4Q,187
99
- runtimepy/data/schemas/ConnectionArbiterConfig.yaml,sha256=WorY7ttxvQA78TYuFoNHw41hc9johxvgO72dusfLSqE,2133
98
+ runtimepy/data/schemas/ClientConnectionConfig.yaml,sha256=biBuRiKUx6kSC5GdO1zdia878n8Cqz4xCm3mranukqo,206
99
+ runtimepy/data/schemas/ConnectionArbiterConfig.yaml,sha256=iZI3psx0_v7TBiC_qae0mf1FNs615ZMXBTcp7SQrF-c,2203
100
100
  runtimepy/data/schemas/EnumRegistry.yaml,sha256=BfLzEEUsHj6Fg_0JyGmgbNJ7F-auuLs5tAhJjSc86uU,145
101
101
  runtimepy/data/schemas/FindFile.yaml,sha256=dSPCDQy4FQZLMgOjtbR0-o2sZECvN_tvGa3LXNd1-wc,934
102
- runtimepy/data/schemas/PeerProcessConfig.yaml,sha256=RNVGG1NV9-Goa7aLE0ah7QNwKOTEoJj6EZDXTW-TALM,190
102
+ runtimepy/data/schemas/PeerProcessConfig.yaml,sha256=SA2DnZImkM8hfxLmg6N7r4sUHEdrL0FtYaDdsl1cIAQ,209
103
103
  runtimepy/data/schemas/RuntimeEnum.yaml,sha256=P3SqlxJ7d_tbZlHZBZy2cCcnOASP8APwYKzAwITd7Kg,518
104
104
  runtimepy/data/schemas/ServerConnectionConfig.yaml,sha256=IqQUQB09xte4zGmM6Qi0-LTm5McDkoi2tehYspoNUXM,100
105
105
  runtimepy/data/schemas/StructConfig.yaml,sha256=KXcHMYsM5JgsIlHhfXW8tLx5GuekS6m5jsgPCm-_tZ4,175
106
106
  runtimepy/data/schemas/TaskConfig.yaml,sha256=upEfToPllsqEcDoJf9D3rbvXk08nc0slmlUSMyCOYcQ,247
107
+ runtimepy/data/schemas/TwoTupleArray.yaml,sha256=HmZhgszwzSjj6j3GVAn6QNjPFaHGut9SZfskGWNoeXI,112
107
108
  runtimepy/data/schemas/channel_controls.yaml,sha256=pctqV_fVjRpiKdaPqET7yyoGVYQuUtOYc1FLQUdfVJc,546
108
109
  runtimepy/data/schemas/has_config.yaml,sha256=SMuJ9tNWw06tsgDasz4myO9SSmMZGep9xBfJ89GJnqA,80
109
110
  runtimepy/data/schemas/has_factory.yaml,sha256=Rsqrxv3HEBUGxPcW6CN7QczA96iBSgtm0gQNsu2P8LM,106
110
111
  runtimepy/data/schemas/has_markdown.yaml,sha256=LbnEQRYdk5KR_GgORmIOiKjRg-HF8wjhA6Dm6pSm66I,45
111
112
  runtimepy/data/schemas/has_name.yaml,sha256=I5YkXxQRYz-1-49CLyr_NA2zVqyRVQCAsb-icTaxF4s,59
112
113
  runtimepy/data/schemas/has_request_flag.yaml,sha256=S8ly8g-FkrCVNEizbXPqicg_hpGvtH7WRsHZAA4uhjc,66
114
+ runtimepy/data/schemas/has_views.yaml,sha256=X-V30he_Y_l_T8teMCROp4byaJNK9I3tihE5YhP8Le8,82
113
115
  runtimepy/data/static/css/bootstrap-icons.min.css,sha256=YWcTOU0uDzjc0ziOtRfrECKA-JAeU4SYUgIHmPwkqSk,87029
114
116
  runtimepy/data/static/css/bootstrap.min.css,sha256=x7AwauKmt5DrGTlkPvW6439HiL-5Pjd1doeExMdCx3M,231973
115
117
  runtimepy/data/static/css/fonts/bootstrap-icons.woff,sha256=9VUTt7WRy4SjuH_w406iTUgx1v7cIuVLkRymS1tUShU,180288
@@ -167,17 +169,17 @@ runtimepy/net/ssl.py,sha256=dj9uECPKDT5k-5vlR5I3Z7Go3WWZhbaJ9nb0rC3kJvg,854
167
169
  runtimepy/net/util.py,sha256=XTQQ-Ql_ImhVd1_O8nSeDX9MY8xJwRBggvliSLCrsc8,5913
168
170
  runtimepy/net/apps/__init__.py,sha256=vjo7e19QXtJwe6V6B-QGvYiJveYobnYIfpkKZrnS17w,710
169
171
  runtimepy/net/arbiter/__init__.py,sha256=ptKF995rYKvkm4Mya92vA5QEDqcFq5NRD0IYGqZ6_do,740
170
- runtimepy/net/arbiter/base.py,sha256=q9mQ3vjVjlzjGrDcTq8gengsEV2AnCUx8IK_40h6uxg,15011
172
+ runtimepy/net/arbiter/base.py,sha256=s7fyyC7MSLu3qD472vkcmKNZfinMuoTWNUlv0kT8HZw,15467
171
173
  runtimepy/net/arbiter/info.py,sha256=QcBB1LQELXPs-Ud-GVq3aDBL4mpSMDcjjLtuKgojiU8,10962
172
174
  runtimepy/net/arbiter/result.py,sha256=PHZo5qj4SI08ZeWPFk_8OZ1umI6L0dp5nJpjjS8QUpM,2871
173
175
  runtimepy/net/arbiter/task.py,sha256=APcc5QioAG8uueIzxJU-vktIn8Ys3yJd_CFlRWb6Ieo,795
174
176
  runtimepy/net/arbiter/udp.py,sha256=-ecHJs-utcsiTfr5wSb73hUUuYFBeRVT_D1znYp5q6A,893
175
177
  runtimepy/net/arbiter/websocket.py,sha256=vYTDA7sXMUTTqW3i1zTWUdaxGKxfrQcQoVSYZtmCvfQ,1524
176
- runtimepy/net/arbiter/config/__init__.py,sha256=NnsVUllwHGAOVhQYAhFIYq1Il5xQdP86bNPrqzwL0oQ,8678
177
- runtimepy/net/arbiter/config/codec.py,sha256=TQj8UXEb1EvhiCqRdyq5BkeubMytEZAs9B4E5ZYsEuY,2511
178
+ runtimepy/net/arbiter/config/__init__.py,sha256=sHiXni5s93VnmWu1SaoYuM5rK_CQejj0CDb_S6pQTHs,8775
179
+ runtimepy/net/arbiter/config/codec.py,sha256=JVutIe1AFVr3NN7GS4rZayxZR05LWzQZRqzEuJpEJd8,2635
178
180
  runtimepy/net/arbiter/config/util.py,sha256=MezLSil5mEwioI5kxDOZa9y118st1_t0El8DYH6hFU8,1254
179
181
  runtimepy/net/arbiter/factory/__init__.py,sha256=jC1szUYucH4Us3jbb0mhFgnklHlorya5DYGGw2pqfe4,334
180
- runtimepy/net/arbiter/factory/connection.py,sha256=uSwnvIWGJcDd2ReK-s9lBx-NcRQ1JH_7VbwkWjE_8zA,3690
182
+ runtimepy/net/arbiter/factory/connection.py,sha256=MFdO82g2VrUaXwmqDGGWpt2AjhlYyCqH7gW-ELAMtNs,3797
181
183
  runtimepy/net/arbiter/factory/task.py,sha256=YLRv55dnDBqHRJIMYgO9_uHi0AW-8hwa0n3wHAKyncE,1959
182
184
  runtimepy/net/arbiter/housekeeping/__init__.py,sha256=-6P2x_qSWp1juml0wKZGJ343c-atrbp8YkDRWn162UA,3622
183
185
  runtimepy/net/arbiter/imports/__init__.py,sha256=W7-kkM4B_zDU42Fyh0PmZL56JslS_0_qzvpzUhN6aDU,5041
@@ -198,7 +200,7 @@ runtimepy/net/http/request_target.py,sha256=EfcOozUeXqOuQaMXH9cErfJqUkG0A5v9HEK4
198
200
  runtimepy/net/http/response.py,sha256=fD0R_BUgmNwdwKQtXvYfTYM7DyJlwsGmlNVi5HkCOhU,3409
199
201
  runtimepy/net/http/state.py,sha256=qCMN8aWfCRfU9XP-cIhSOo2RqfljTjbQRCflfcy2bfY,1626
200
202
  runtimepy/net/http/version.py,sha256=mp6rgIM7-VUVKLCA0Uw96CmBkL0ET860lDVVEewpZ7w,1098
201
- runtimepy/net/server/__init__.py,sha256=5KalIcOWv8lYm8747pq2rzGwpLz713XdHuQIKbWJsXc,11649
203
+ runtimepy/net/server/__init__.py,sha256=ppfMgymYGRz13MvHvwXyy9WAos2wWgaZDf1TW8D1ILU,11813
202
204
  runtimepy/net/server/html.py,sha256=OB2K37kA7MHtcKqp0pZE1q_XgiyvfooigzS0-OQFCCM,1900
203
205
  runtimepy/net/server/json.py,sha256=AaMPw-G-7xX67mf1LvQAipNdwrnmbLDunVlkWf6iOz0,2526
204
206
  runtimepy/net/server/markdown.py,sha256=UIJ9R9WM5XodPs8WEevFNJ3LX9tMevhUe8QKKdeY4ak,2143
@@ -216,7 +218,7 @@ runtimepy/net/server/app/tab.py,sha256=N4NYvxeo0fllb404aCHn7YKhlY6ZnG6G4HBiMS17q
216
218
  runtimepy/net/server/app/env/__init__.py,sha256=vgiPIYkitx0aqtmgG_nkOehDM7vrQJHYkhRsGCP8pU8,4877
217
219
  runtimepy/net/server/app/env/modal.py,sha256=HTipCYgQaAUtsmlBjXKfhAM5JyhLqoIIwEwsPnKhrG8,1740
218
220
  runtimepy/net/server/app/env/settings.py,sha256=m87hHAapuNq0xKzDNSNTwG8D2Cb3QFSVrziszf8iVHs,1631
219
- runtimepy/net/server/app/env/widgets.py,sha256=sDfJYBVIXZuly4Rvch597Y-LTT6t3obxc60oejqGv7g,7104
221
+ runtimepy/net/server/app/env/widgets.py,sha256=jghzleoD3EsUO8GNeeHv51DstXfa-maviDK0hoahmvo,7730
220
222
  runtimepy/net/server/app/env/tab/__init__.py,sha256=stTVKyHljLQWnnhxkWPwa7bLdZtjhiMFbiVFgbiYaFI,647
221
223
  runtimepy/net/server/app/env/tab/base.py,sha256=mljE6n56HUwcWO1lrjj5PR7qh5dvY8CZYMwDcrV-yVk,1199
222
224
  runtimepy/net/server/app/env/tab/controls.py,sha256=11TidvphKyvLCgdW8Sjiyd6BpX4-ybGZPEhrn-hzkuU,8263
@@ -283,7 +285,7 @@ runtimepy/registry/name.py,sha256=TkNm7kff_Id6p_b9jr8YTi1UN1xCNzwk38IEomE7o5Q,19
283
285
  runtimepy/sample/__init__.py,sha256=N7P6hnCLF9NwnkZA1h3LzS2C334SAO48Fu8adHxWGLU,56
284
286
  runtimepy/sample/peer.py,sha256=uNlIPAv1-wjGUWdR0AM3L9NUMjnIMJBqQ9ZsHdTLx3Q,1688
285
287
  runtimepy/sample/program.py,sha256=AFqinsnsjzatgJXePAO4yXYerxmzN7ajtDmJPwWigYc,2428
286
- runtimepy/struct/__init__.py,sha256=Q7t1qKpuYGjtRGXdC_x8IwJyyCQ1Xy2wYriud89XJnk,2229
288
+ runtimepy/struct/__init__.py,sha256=m-ZAP-_L_1ezAIbCPrhcBPN_R0vLv5Pc97eiFVDpn2w,2300
287
289
  runtimepy/subprocess/__init__.py,sha256=VAiFrYFCU5ETDVoWLOVlrrSsx2d1_atYXUfXYc_OQ9g,4059
288
290
  runtimepy/subprocess/interface.py,sha256=4nGVUfDThaZrfqgn2nZHMt1hfUwHezSvFjykBXGT36g,8041
289
291
  runtimepy/subprocess/peer.py,sha256=oYw9a0yKAPR18Z6Qt24wYWrcX6EizeQE64htL11WVjM,7593
@@ -294,7 +296,7 @@ runtimepy/task/asynchronous.py,sha256=w4oEUCyj-X-zDVFmlsAtRL1gv66ahQ78QKE0GmLGT1
294
296
  runtimepy/task/sample.py,sha256=_nbLj5Julwa1NJC_-WQsotI0890G-TlOWftVHEKiclY,2735
295
297
  runtimepy/task/basic/__init__.py,sha256=NryfG-JmSyqYh-TNG4NLO6-9RJFVq5vn1Z-oV3qTVvg,243
296
298
  runtimepy/task/basic/manager.py,sha256=4dd2k-azYfyKS6jiCK9MCL-yHomuq32maicpjZvrOjA,2357
297
- runtimepy/task/basic/periodic.py,sha256=81ACFNzttJh2PQryHUA8La9MJvDUOSTxfiXkqtaOK4M,7595
299
+ runtimepy/task/basic/periodic.py,sha256=vADMqQ5o9ZpWJjf9_Kks-uCSvx_Pq7GUWgF5wdkAozs,7671
298
300
  runtimepy/task/trig/__init__.py,sha256=GuGNb9eLuFEnl3nAI7Mi_eS5mqJ4MOhEy2Wfv48RFic,785
299
301
  runtimepy/telemetry/__init__.py,sha256=G_JLZsp0EZMGaxSQ12fYgbG2kN4QkvVG4lExV_TzEhM,268
300
302
  runtimepy/telemetry/sample.py,sha256=1weoGSH-yGg-fOaLysZAsO3dSTM6yAXX3XdulAiqi3s,3216
@@ -306,9 +308,9 @@ runtimepy/tui/task.py,sha256=nUZo9fuOC-k1Wpqdzkv9v1tQirCI28fZVgcC13Ijvus,1093
306
308
  runtimepy/tui/channels/__init__.py,sha256=evDaiIn-YS9uGhdo8ZGtP9VK1ek6sr_P1nJ9JuSET0o,4536
307
309
  runtimepy/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
308
310
  runtimepy/ui/controls.py,sha256=L55Af-4vGq6ZHewdoA7C_mAYq35WXl8NzOdcsmQIo7M,1868
309
- runtimepy-5.15.2.dist-info/licenses/LICENSE,sha256=yKBRwbO-cOPBrlpsZmJkkSa33DfY31aE8t7lZ0DwlUo,1071
310
- runtimepy-5.15.2.dist-info/METADATA,sha256=6UbqbnIRB9WTeD5cDcSUfCqcqlxEEC6o5CQgPSBAohM,9268
311
- runtimepy-5.15.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
312
- runtimepy-5.15.2.dist-info/entry_points.txt,sha256=-btVBkYv7ybcopqZ_pRky-bEzu3vhbaG3W3Z7ERBiFE,51
313
- runtimepy-5.15.2.dist-info/top_level.txt,sha256=0jPmh6yqHyyJJDwEID-LpQly-9kQ3WRMjH7Lix8peLg,10
314
- runtimepy-5.15.2.dist-info/RECORD,,
311
+ runtimepy-5.15.4.dist-info/licenses/LICENSE,sha256=yKBRwbO-cOPBrlpsZmJkkSa33DfY31aE8t7lZ0DwlUo,1071
312
+ runtimepy-5.15.4.dist-info/METADATA,sha256=1G73SimzqDIEjYrlCRLPQ5haVEZX2KGsCKyP2Lpqm0Q,9268
313
+ runtimepy-5.15.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
314
+ runtimepy-5.15.4.dist-info/entry_points.txt,sha256=-btVBkYv7ybcopqZ_pRky-bEzu3vhbaG3W3Z7ERBiFE,51
315
+ runtimepy-5.15.4.dist-info/top_level.txt,sha256=0jPmh6yqHyyJJDwEID-LpQly-9kQ3WRMjH7Lix8peLg,10
316
+ runtimepy-5.15.4.dist-info/RECORD,,