runtimepy 5.15.7__py3-none-any.whl → 5.16.0__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=7591d3ee09b156575678bdf806e1b5c7
4
+ # hash=d903df789fdb4c76fdf462319413ca2c
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.7"
13
+ VERSION = "5.16.0"
14
14
 
15
15
  # runtimepy-specific content.
16
16
  METRICS_NAME = "metrics"
@@ -21,6 +21,10 @@ NonStructHandler = Callable[[BytesIO], bool]
21
21
  NON_STRUCT_ID = 0
22
22
 
23
23
 
24
+ def null_struct_handler(_: Protocol) -> None:
25
+ """Takes no action."""
26
+
27
+
24
28
  class StructReceiver(LoggerMixin):
25
29
  """A class for sending and receiving struct messages."""
26
30
 
@@ -44,7 +48,9 @@ class StructReceiver(LoggerMixin):
44
48
  assert self.non_struct_handler is None
45
49
  self.non_struct_handler = handler
46
50
 
47
- def add_handler(self, identifier: int, handler: StructHandler) -> None:
51
+ def add_handler(
52
+ self, identifier: int, handler: StructHandler = null_struct_handler
53
+ ) -> None:
48
54
  """Add a struct message handler."""
49
55
 
50
56
  assert identifier not in self.handlers
@@ -30,7 +30,9 @@ async def entry(
30
30
 
31
31
  await arbiter.load_configs(args.configs, wait_for_stop=args.wait_for_stop)
32
32
 
33
- return await arbiter.app()
33
+ if args.init_only:
34
+ stop_sig.set()
35
+ return await arbiter.app(clear_stop_sig=not args.init_only)
34
36
 
35
37
 
36
38
  def app(args: _Namespace) -> int:
@@ -38,9 +40,6 @@ def app(args: _Namespace) -> int:
38
40
 
39
41
  stop_sig = _asyncio.Event()
40
42
 
41
- if args.init_only:
42
- stop_sig.set()
43
-
44
43
  result = _run_handle_stop(
45
44
  stop_sig,
46
45
  entry(stop_sig, args, window=args.window),
@@ -19,6 +19,8 @@ body > :first-child {
19
19
 
20
20
  #runtimepy-tabs {
21
21
  width: min-content;
22
+ max-width: 30vw;
23
+ overflow: hidden;
22
24
  }
23
25
 
24
26
  #runtimepy-splash {
@@ -342,7 +342,11 @@ class JsonMessageInterface:
342
342
  target = self.targets.evaluate(key)
343
343
  if target:
344
344
  assert target.data is not None
345
- key, handler, kind = target.data
345
+ ( # pylint: disable=unpacking-non-sequence
346
+ key,
347
+ handler,
348
+ kind,
349
+ ) = target.data
346
350
 
347
351
  # Use target resolution data (if any) as a base.
348
352
  with_sub_data = copy(
@@ -237,9 +237,10 @@ class BaseConnectionArbiter(_NamespaceMixin, _LoggerMixin, TuiMixin):
237
237
  self._register_connection(value, key)
238
238
 
239
239
  # Ensure connections are all initialized.
240
- await _asyncio.gather(
241
- *(x.initialized.wait() for x in self._connections.values())
242
- )
240
+ with self.log_time("Connection initialization", reminder=True):
241
+ await _asyncio.gather(
242
+ *(x.initialized.wait() for x in self._connections.values())
243
+ )
243
244
 
244
245
  async def _build_structs(self, info: AppInfo) -> None:
245
246
  """Build structs."""
@@ -362,6 +363,7 @@ class BaseConnectionArbiter(_NamespaceMixin, _LoggerMixin, TuiMixin):
362
363
  app: NetworkApplicationlike = None,
363
364
  check_connections: bool = True,
364
365
  config: _JsonObject = None,
366
+ clear_stop_sig: bool = True,
365
367
  ) -> int:
366
368
  """
367
369
  Ensures connections are given a chance to initialize, run the
@@ -372,6 +374,9 @@ class BaseConnectionArbiter(_NamespaceMixin, _LoggerMixin, TuiMixin):
372
374
  info: Optional[AppInfo] = None
373
375
 
374
376
  try:
377
+ if clear_stop_sig:
378
+ self.stop_sig.clear()
379
+
375
380
  async with _AsyncExitStack() as stack:
376
381
  result, info = await self._main(
377
382
  stack,
@@ -462,6 +467,7 @@ class BaseConnectionArbiter(_NamespaceMixin, _LoggerMixin, TuiMixin):
462
467
  app: NetworkApplicationlike = None,
463
468
  check_connections: bool = True,
464
469
  config: _JsonObject = None,
470
+ clear_stop_sig: bool = False,
465
471
  ) -> int:
466
472
  """
467
473
  Run the application alongside the connection manager and server tasks.
@@ -472,7 +478,10 @@ class BaseConnectionArbiter(_NamespaceMixin, _LoggerMixin, TuiMixin):
472
478
 
473
479
  # Run application.
474
480
  result = await self._entry(
475
- app=app, check_connections=check_connections, config=config
481
+ app=app,
482
+ check_connections=check_connections,
483
+ config=config,
484
+ clear_stop_sig=clear_stop_sig,
476
485
  )
477
486
 
478
487
  # Shutdown any pending tasks.
@@ -69,7 +69,10 @@ class RuntimeStruct(RuntimeStructBase):
69
69
  final_poll = False
70
70
 
71
71
  def init_env(self) -> None:
72
- """Initialize this sample environment."""
72
+ """Initialize this environment."""
73
+
74
+ async def async_init_env(self) -> None:
75
+ """Initialize this environment."""
73
76
 
74
77
  @contextmanager
75
78
  def _final_poll(self) -> _Iterator[None]:
@@ -101,14 +104,18 @@ class RuntimeStruct(RuntimeStructBase):
101
104
  if ProtocolFactory in factory.__bases__:
102
105
  self.recv = factory.singleton()
103
106
  byte_order = self.recv.byte_order
104
- with self.env.names_pushed("rx"):
107
+ if self.config.get("control", True):
108
+ with self.env.names_pushed("rx"):
109
+ self.env.register_protocol(self.recv, False)
110
+
111
+ self.send = factory.instance()
112
+ with self.env.names_pushed("tx"):
113
+ self.env.register_protocol(self.send, True)
114
+ else:
105
115
  self.env.register_protocol(self.recv, False)
106
116
 
107
- self.send = factory.instance()
108
- with self.env.names_pushed("tx"):
109
- self.env.register_protocol(self.send, True)
110
-
111
117
  self.init_env()
118
+ await self.async_init_env()
112
119
  self.update_byte_order(byte_order, **kwargs)
113
120
 
114
121
  def update_byte_order(self, byte_order: ByteOrder, **kwargs) -> None:
@@ -43,6 +43,7 @@ class Connection(
43
43
  byte_order: ByteOrder = DEFAULT_BYTE_ORDER
44
44
 
45
45
  default_auto_restart = False
46
+ ignore_stop_sig = False
46
47
 
47
48
  def __init__(
48
49
  self,
@@ -300,7 +301,7 @@ class Connection(
300
301
  )
301
302
 
302
303
  # Allow a stop signal to also disable the connection.
303
- if stop_sig is not None:
304
+ if stop_sig is not None and not self.ignore_stop_sig:
304
305
  self._tasks.append(_asyncio.create_task(self._wait_sig(stop_sig)))
305
306
 
306
307
  self.exited.clear()
@@ -3,11 +3,12 @@ A module implementing HTTP-response interfaces.
3
3
  """
4
4
 
5
5
  # built-in
6
+ from abc import ABC, abstractmethod
6
7
  import http
7
8
  from io import StringIO
8
9
  import logging
9
10
  from pathlib import Path
10
- from typing import AsyncIterator, cast
11
+ from typing import AsyncIterator, Optional, cast
11
12
 
12
13
  # third-party
13
14
  import aiofiles
@@ -96,19 +97,32 @@ class ResponseHeader(HeadersMixin):
96
97
  self["Cache-Control"] = value
97
98
 
98
99
 
99
- class AsyncResponse:
100
+ class AsyncResponse(ABC):
101
+ """Interface for asynchronous responses."""
102
+
103
+ @abstractmethod
104
+ async def size(self) -> Optional[int]:
105
+ """Get this response's size."""
106
+
107
+ @abstractmethod
108
+ async def process(self) -> AsyncIterator[bytes]:
109
+ """Yield chunks to write asynchronously."""
110
+ yield bytes() # pragma: nocover
111
+
112
+
113
+ class AsyncFile(AsyncResponse):
100
114
  """
101
115
  A class facilitating asynchronous server responses for e.g.
102
116
  file-system files.
103
117
  """
104
118
 
105
- def __init__(self, path: Path, chunk_size: int = 1024) -> None:
119
+ def __init__(self, path: Path, chunk_size: int = 4096) -> None:
106
120
  """Initialize this instance."""
107
121
 
108
122
  self.path = path
109
123
  self.chunk_size = chunk_size
110
124
 
111
- async def size(self) -> int:
125
+ async def size(self) -> Optional[int]:
112
126
  """Get this response's size."""
113
127
  return cast(int, await aiofiles.os.path.getsize(self.path))
114
128
 
@@ -8,7 +8,7 @@ from io import StringIO
8
8
  import logging
9
9
  import mimetypes
10
10
  from pathlib import Path
11
- from typing import Any, Optional, TextIO, Union
11
+ from typing import Any, Awaitable, Callable, Optional, TextIO, Union
12
12
  from urllib.parse import urlencode
13
13
 
14
14
  # third-party
@@ -22,7 +22,7 @@ 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
25
- from runtimepy.net.http.response import AsyncResponse, ResponseHeader
25
+ from runtimepy.net.http.response import AsyncFile, ResponseHeader
26
26
  from runtimepy.net.server.html import HtmlApp, HtmlApps, get_html, html_handler
27
27
  from runtimepy.net.server.json import encode_json, json_handler
28
28
  from runtimepy.net.server.markdown import DIR_FILE, markdown_for_dir
@@ -41,11 +41,17 @@ def package_data_dir() -> Path:
41
41
  return result.parent
42
42
 
43
43
 
44
+ CustomAsync = Callable[
45
+ [ResponseHeader, RequestHeader, Optional[bytearray]], Awaitable[HttpResult]
46
+ ]
47
+
48
+
44
49
  class RuntimepyServerConnection(HttpConnection):
45
50
  """A class implementing a server-connection interface for this package."""
46
51
 
47
52
  # Can register application methods to URL paths.
48
53
  apps: HtmlApps = {"/mux.html": mux_app}
54
+ custom: dict[str, CustomAsync] = {}
49
55
  default_app: Optional[HtmlApp] = None
50
56
 
51
57
  # Can load additional data into this dictionary for easy HTTP access.
@@ -245,7 +251,7 @@ class RuntimepyServerConnection(HttpConnection):
245
251
  response.static_resource()
246
252
 
247
253
  # Return the file data.
248
- result = AsyncResponse(candidate)
254
+ result = AsyncFile(candidate)
249
255
  break
250
256
 
251
257
  # Handle a directory as a last resort.
@@ -335,6 +341,12 @@ class RuntimepyServerConnection(HttpConnection):
335
341
  response.static_resource()
336
342
  return self.favicon_data
337
343
 
344
+ # Check for a custom handler.
345
+ if path in self.custom:
346
+ return await self.custom[path](
347
+ response, request, request_data
348
+ )
349
+
338
350
  # Try serving a file and handling redirects.
339
351
  for handler in [self.try_redirect, self.try_file]:
340
352
  result = await handler(
@@ -173,13 +173,13 @@ class HttpConnection(_TcpConnection):
173
173
  ) -> None:
174
174
  """Send a request or response to a request."""
175
175
 
176
- # Set content length.
177
- header["content-length"] = "0"
178
-
176
+ size = None
179
177
  if isinstance(data, AsyncResponse):
180
- header["content-length"] = str(await data.size())
178
+ size = await data.size()
181
179
  elif data is not None:
182
- header["content-length"] = str(len(data))
180
+ size = len(data)
181
+ if size is not None:
182
+ header["content-length"] = str(size)
183
183
 
184
184
  self.send_binary(bytes(header))
185
185
 
@@ -104,9 +104,7 @@ class WebsocketConnection(Connection):
104
104
 
105
105
  async def _send_binay_message(self, data: BinaryMessage) -> None:
106
106
  """Send a binary message."""
107
- await self._handle_connection_closed(
108
- self.protocol.send(data), # type: ignore
109
- )
107
+ await self._handle_connection_closed(self.protocol.send(data))
110
108
  self.metrics.tx.increment(len(data))
111
109
 
112
110
  async def close(self) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: runtimepy
3
- Version: 5.15.7
3
+ Version: 5.16.0
4
4
  Summary: A framework for implementing Python services.
5
5
  Home-page: https://github.com/libre-embedded/runtimepy
6
6
  Author: Libre Embedded
@@ -51,11 +51,11 @@ Dynamic: requires-python
51
51
  =====================================
52
52
  generator=datazen
53
53
  version=3.2.3
54
- hash=fd0b9f87927033d8ee2eb5448d8aec76
54
+ hash=ebb0bba9899d4baf7ce73b082f5e384e
55
55
  =====================================
56
56
  -->
57
57
 
58
- # runtimepy ([5.15.7](https://pypi.org/project/runtimepy/))
58
+ # runtimepy ([5.16.0](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)
@@ -89,7 +89,7 @@ This package is tested on the following platforms:
89
89
  # Command-line Options
90
90
 
91
91
  ```
92
- $ ./venv3.12/bin/runtimepy -h
92
+ $ ./venv3.13/bin/runtimepy -h
93
93
 
94
94
  usage: runtimepy [-h] [--version] [-v] [-q] [--curses] [--no-uvloop] [-C DIR]
95
95
  {arbiter,mtu,server,task,tftp,tui,noop} ...
@@ -103,7 +103,7 @@ options:
103
103
  -q, --quiet set to reduce output
104
104
  --curses whether or not to use curses.wrapper when starting
105
105
  --no-uvloop whether or not to disable uvloop as event loop driver
106
- -C DIR, --dir DIR execute from a specific directory
106
+ -C, --dir DIR execute from a specific directory
107
107
 
108
108
  commands:
109
109
  {arbiter,mtu,server,task,tftp,tui,noop}
@@ -123,7 +123,7 @@ commands:
123
123
  ### `arbiter`
124
124
 
125
125
  ```
126
- $ ./venv3.12/bin/runtimepy arbiter -h
126
+ $ ./venv3.13/bin/runtimepy arbiter -h
127
127
 
128
128
  usage: runtimepy arbiter [-h] [-i] [-w] [--no-poller] configs [configs ...]
129
129
 
@@ -144,7 +144,7 @@ options:
144
144
  ### `mtu`
145
145
 
146
146
  ```
147
- $ ./venv3.12/bin/runtimepy mtu -h
147
+ $ ./venv3.13/bin/runtimepy mtu -h
148
148
 
149
149
  usage: runtimepy mtu [-h] [--probe-size PROBE_SIZE] [--fallback FALLBACK] [-t]
150
150
  destination [destination ...]
@@ -165,7 +165,7 @@ options:
165
165
  ### `server`
166
166
 
167
167
  ```
168
- $ ./venv3.12/bin/runtimepy server -h
168
+ $ ./venv3.13/bin/runtimepy server -h
169
169
 
170
170
  usage: runtimepy server [-h] [-i] [-w] [--no-poller] [--cafile CAFILE]
171
171
  [--capath CAPATH] [--cadata CADATA]
@@ -191,7 +191,7 @@ options:
191
191
  --certfile CERTFILE passed directly to instantiation
192
192
  --keyfile KEYFILE passed directly to instantiation
193
193
  --host HOST host address to listen on (default: '0.0.0.0')
194
- -p PORT, --port PORT port to listen on (default: 0)
194
+ -p, --port PORT port to listen on (default: 0)
195
195
  -u, --udp whether or not this is a UDP-based server (otherwise
196
196
  it must be a TCP-based server)
197
197
  -l, --loopback if true a client of the same connection type is added
@@ -201,7 +201,7 @@ options:
201
201
  ### `task`
202
202
 
203
203
  ```
204
- $ ./venv3.12/bin/runtimepy task -h
204
+ $ ./venv3.13/bin/runtimepy task -h
205
205
 
206
206
  usage: runtimepy task [-h] [-i] [-w] [--no-poller] [-r RATE]
207
207
  factory [configs ...]
@@ -218,14 +218,14 @@ options:
218
218
  ensure that a 'wait_for_stop' application method is
219
219
  run last
220
220
  --no-poller don't run a connection-metrics poller task
221
- -r RATE, --rate RATE rate (in Hz) that the task should run (default: 10)
221
+ -r, --rate RATE rate (in Hz) that the task should run (default: 10)
222
222
 
223
223
  ```
224
224
 
225
225
  ### `tftp`
226
226
 
227
227
  ```
228
- $ ./venv3.12/bin/runtimepy tftp -h
228
+ $ ./venv3.13/bin/runtimepy tftp -h
229
229
 
230
230
  usage: runtimepy tftp [-h] [-p PORT] [-m MODE] [-t TIMEOUT] [-r REEMIT]
231
231
  {read,write} host our_file [their_file]
@@ -238,28 +238,27 @@ positional arguments:
238
238
 
239
239
  options:
240
240
  -h, --help show this help message and exit
241
- -p PORT, --port PORT port to message (default: 69)
242
- -m MODE, --mode MODE tftp mode to use (default: octet)
243
- -t TIMEOUT, --timeout TIMEOUT
241
+ -p, --port PORT port to message (default: 69)
242
+ -m, --mode MODE tftp mode to use (default: octet)
243
+ -t, --timeout TIMEOUT
244
244
  timeout for each step
245
- -r REEMIT, --reemit REEMIT
246
- transmit period for each step
245
+ -r, --reemit REEMIT transmit period for each step
247
246
 
248
247
  ```
249
248
 
250
249
  ### `tui`
251
250
 
252
251
  ```
253
- $ ./venv3.12/bin/runtimepy tui -h
252
+ $ ./venv3.13/bin/runtimepy tui -h
254
253
 
255
254
  usage: runtimepy tui [-h] [-i ITERATIONS] [-r RATE]
256
255
 
257
256
  options:
258
257
  -h, --help show this help message and exit
259
- -i ITERATIONS, --iterations ITERATIONS
258
+ -i, --iterations ITERATIONS
260
259
  maximum number of program iterations (if greater than
261
260
  zero, default: 0)
262
- -r RATE, --rate RATE frequency (in Hz) to run the interface (default: 60.0
261
+ -r, --rate RATE frequency (in Hz) to run the interface (default: 60.0
263
262
  Hz)
264
263
 
265
264
  ```
@@ -1,4 +1,4 @@
1
- runtimepy/__init__.py,sha256=7thnFUqjyVartp9aKm12dnNSAnzERRQ8j2AimmJPTPk,391
1
+ runtimepy/__init__.py,sha256=vfEvMM1d1yUUOlAMN1gpJaem2rcm3kFZyR_VA2DthBk,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
@@ -27,11 +27,11 @@ runtimepy/codec/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
27
  runtimepy/codec/protocol/__init__.py,sha256=0mdPIb5mpkqofClqW23kslsgc3V_aSKJ1RmjEHmKfeI,1673
28
28
  runtimepy/codec/protocol/base.py,sha256=kxnFcS-6P75jyK4Vs2H9dIls_PCVnvrbiM9zU6EBroE,12532
29
29
  runtimepy/codec/protocol/json.py,sha256=utBq0kBHJifTklHvSGWNxR6jXb_F3Lzp_qU1Fshsfks,4530
30
- runtimepy/codec/protocol/receiver.py,sha256=RGfpTNiFB_ZtDXtnMYSQ6oO3HiIJKcwCSwoIgvtMsbY,4085
30
+ runtimepy/codec/protocol/receiver.py,sha256=jqPT_BLa58mDy9OQVYT8nufJQxw6769th4ZZm6aQRs8,4196
31
31
  runtimepy/codec/system/__init__.py,sha256=CAdHddEvqbh-Uy-l_9yc0O5VAfuqYvElnuQ4qRG8Y-A,8101
32
32
  runtimepy/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
33
  runtimepy/commands/all.py,sha256=eAn52vuAgOh0jr93LROfbTjSPuJILGFRCPB9UeS3Q1c,1537
34
- runtimepy/commands/arbiter.py,sha256=9xcKnI1Sogmmv8J6FnjuY3zIEgSacmD7pZgAStuWTcc,1616
34
+ runtimepy/commands/arbiter.py,sha256=8q44W-h9IZ2UMkiOrqh0vBNRE1TWVDXsSjzzD2eImfI,1648
35
35
  runtimepy/commands/common.py,sha256=NvZdeIFBHAF52c1n7vqD59DW6ywc-rG5iC5MpuhGf-c,2449
36
36
  runtimepy/commands/mtu.py,sha256=LFFjTU4SsuV3j7Mhx_WuKa5lfdfMm70zJvDWToVrP7E,1357
37
37
  runtimepy/commands/server.py,sha256=q49WlQQWYBcHrKQo7hCc3Y6hNbG2DNLMXIlLg8Mc8lA,4655
@@ -55,7 +55,7 @@ runtimepy/data/server_dev.yaml,sha256=nQsPh7LuQig3pzHfdg_aD3yOUiCj1sKKfI-WwW3hXm
55
55
  runtimepy/data/tftp_server.yaml,sha256=-bFOWJSagI-fEQQcT8k7eDMJVfSPm2XAxLVG3dqUTa4,204
56
56
  runtimepy/data/css/bootstrap_extra.css,sha256=0NiTnZWnIYf04n9NHVe-nVSOLwePJ6X-3uCgUgAEKPI,3101
57
57
  runtimepy/data/css/font.css,sha256=Pe82E66rNi-cwlQ-_1GHAuhPGu5L4x5KqgV0dbDe51w,977
58
- runtimepy/data/css/main.css,sha256=ohZ98-ffw6U1h2Azj8ToYiXFurQo1rH9r6kFQZkrtQ0,1355
58
+ runtimepy/data/css/main.css,sha256=1c7bpU8OwuKSvp0q_mF0g0bRZISIOYPKwAk8mmoSqSY,1394
59
59
  runtimepy/data/js/DataConnection.js,sha256=DnX8FMehjJXqmI62UMYXSvl_XdfQMzq3XUDFbLu2GgI,98
60
60
  runtimepy/data/js/JsonConnection.js,sha256=rclZrbmWc_zSs6I_JhOgxnVPFIyPMo5WdjAe8alyZ3o,2729
61
61
  runtimepy/data/js/audio.js,sha256=bLkBqbeHMiGGidfL3iXjmVoF9seK-ZeZ3kwgOrcpgk4,1092
@@ -146,7 +146,7 @@ runtimepy/enum/registry.py,sha256=Pu-q4s_Mt1EWqizhc4Qzx5a9dMEI2Zgb3_ZwQH1HW9A,32
146
146
  runtimepy/enum/types.py,sha256=uQYGvaAJVm5tUdwxn_SLHkTZHJpEf7364rTSL27necA,1027
147
147
  runtimepy/message/__init__.py,sha256=HtEvU2P6r3_4Z6SpL7LUqLeobIYLkJVgeQZiNb3E3D4,3039
148
148
  runtimepy/message/handlers.py,sha256=He9NC7MCkaV2clKc8dTSZ_T8N2l3ATjaTFzBr9n1T34,3775
149
- runtimepy/message/interface.py,sha256=vg25Uhp7wrDFH6v2iRKUBwnCBpjc3JAFjwdu3KArrLo,11285
149
+ runtimepy/message/interface.py,sha256=iILWne4lrfnD9uk60oC74wZwvIO6qYXgZ2NUsVQA7wE,11408
150
150
  runtimepy/message/types.py,sha256=vajDWKW32LjzsfH-eVCCxZTWVctj4_-tjanhnmCqUis,821
151
151
  runtimepy/metrics/__init__.py,sha256=NyCcB3uJi4_tGMO-ws3CPRA2fph2t15BcW_tfeV9fmc,357
152
152
  runtimepy/metrics/channel.py,sha256=rCF_NZ4UaIYV4NExmw0Mskzyd2Npy-c_hFiRe36_bzg,2527
@@ -163,7 +163,7 @@ runtimepy/mixins/regex.py,sha256=kpCj4iL1akzt_KPPiMP-bTbuLBHOpkUrwbCTRe8HSUk,106
163
163
  runtimepy/mixins/trig.py,sha256=vkDd9Rh8080gvH5OHkSYmjImVgM_ZZ7RzMxsczKx5N4,2480
164
164
  runtimepy/net/__init__.py,sha256=HQaWGxnEH49JSPX2Q_N5QNSV0Wd_x0zZQJa1SV1EC_M,790
165
165
  runtimepy/net/backoff.py,sha256=IVloxQd-gEK62gFAlU2aOwgTEXhsNUTBfS16eiOqKG8,1080
166
- runtimepy/net/connection.py,sha256=GZ9rZP7wgUUYWmyL4FGbJzhqb1uNWCQAsNbXSGzoHAw,12872
166
+ runtimepy/net/connection.py,sha256=NwAomSIyC81m68NfGeTN4dQ0sLp52-MbD371Mt7Y7T8,12929
167
167
  runtimepy/net/manager.py,sha256=-M-ZSB9izay6HK1ytTayAYnSHYAz34dcwxaiNhC4lWg,4264
168
168
  runtimepy/net/mixin.py,sha256=0NTKeuaoUNm7--GzA7rxU3gb1rrGGhu1vNj6mek4dDA,3022
169
169
  runtimepy/net/mtu.py,sha256=XnLXAFMsDxK1Lj5v_zgWaBrC3lNqf81DkbDc6hpMdmI,3495
@@ -171,8 +171,8 @@ runtimepy/net/ssl.py,sha256=dj9uECPKDT5k-5vlR5I3Z7Go3WWZhbaJ9nb0rC3kJvg,854
171
171
  runtimepy/net/util.py,sha256=XTQQ-Ql_ImhVd1_O8nSeDX9MY8xJwRBggvliSLCrsc8,5913
172
172
  runtimepy/net/apps/__init__.py,sha256=vjo7e19QXtJwe6V6B-QGvYiJveYobnYIfpkKZrnS17w,710
173
173
  runtimepy/net/arbiter/__init__.py,sha256=ptKF995rYKvkm4Mya92vA5QEDqcFq5NRD0IYGqZ6_do,740
174
- runtimepy/net/arbiter/base.py,sha256=TDWIphAiBR_b7MuieVZM2_PgV-EEFmmmVq-Yjobm13w,15865
175
- runtimepy/net/arbiter/info.py,sha256=QcBB1LQELXPs-Ud-GVq3aDBL4mpSMDcjjLtuKgojiU8,10962
174
+ runtimepy/net/arbiter/base.py,sha256=kG8fyZsYmiddwLuPWxOsR_w6dqvRt2w8f7UFWlFJtqY,16162
175
+ runtimepy/net/arbiter/info.py,sha256=OxzAq0kjhv9VZBSAHwLWApyKbVgLcMyWhOgpI_PlWuE,11239
176
176
  runtimepy/net/arbiter/result.py,sha256=PHZo5qj4SI08ZeWPFk_8OZ1umI6L0dp5nJpjjS8QUpM,2871
177
177
  runtimepy/net/arbiter/task.py,sha256=APcc5QioAG8uueIzxJU-vktIn8Ys3yJd_CFlRWb6Ieo,795
178
178
  runtimepy/net/arbiter/udp.py,sha256=-ecHJs-utcsiTfr5wSb73hUUuYFBeRVT_D1znYp5q6A,893
@@ -199,10 +199,10 @@ runtimepy/net/http/__init__.py,sha256=cMKNPyYZpdT03OR-HNfwzZbaKGchzlGIrK712daRK4
199
199
  runtimepy/net/http/common.py,sha256=vpoO6XwRmrZmTkCu9bkI0HnyaD8MWTpV7ADesCNrfRE,2237
200
200
  runtimepy/net/http/header.py,sha256=AECSdvhBA9_5Pg3UdwMzsmBpcqgsiPj41xnIGPm5g5E,2296
201
201
  runtimepy/net/http/request_target.py,sha256=EfcOozUeXqOuQaMXH9cErfJqUkG0A5v9HEK4tCorSf4,1543
202
- runtimepy/net/http/response.py,sha256=fD0R_BUgmNwdwKQtXvYfTYM7DyJlwsGmlNVi5HkCOhU,3409
202
+ runtimepy/net/http/response.py,sha256=rLllTaaFn3-ABMhq3jM_6-kqq8ym5VJGVWNwmBr3kAI,3823
203
203
  runtimepy/net/http/state.py,sha256=qCMN8aWfCRfU9XP-cIhSOo2RqfljTjbQRCflfcy2bfY,1626
204
204
  runtimepy/net/http/version.py,sha256=mp6rgIM7-VUVKLCA0Uw96CmBkL0ET860lDVVEewpZ7w,1098
205
- runtimepy/net/server/__init__.py,sha256=ppfMgymYGRz13MvHvwXyy9WAos2wWgaZDf1TW8D1ILU,11813
205
+ runtimepy/net/server/__init__.py,sha256=NHs8cXTRTEreVhk5QW9dMTW-pyUCd3NfuATm1a-5V6Y,12191
206
206
  runtimepy/net/server/html.py,sha256=OB2K37kA7MHtcKqp0pZE1q_XgiyvfooigzS0-OQFCCM,1900
207
207
  runtimepy/net/server/json.py,sha256=AaMPw-G-7xX67mf1LvQAipNdwrnmbLDunVlkWf6iOz0,2526
208
208
  runtimepy/net/server/markdown.py,sha256=kKKSGF_HwH8ADnNm5fNnWq4XXh7Td9Iu_QUj_u-qmts,3595
@@ -237,7 +237,7 @@ runtimepy/net/tcp/__init__.py,sha256=OOWohegpoioSTf8M7uDf-4EV1IDungz7-U19L_2yW4I
237
237
  runtimepy/net/tcp/connection.py,sha256=FL9SlODVAehECYgF9eKk8sbDMmTMBGlsGJlGaMncQh4,8793
238
238
  runtimepy/net/tcp/create.py,sha256=zZsRs5KYpO3bNGh-DwEOEzjUDE4ixj-UBHYgZ0GvC7c,2013
239
239
  runtimepy/net/tcp/protocol.py,sha256=vT4HOH-WLrM0j4kUpQA_ZZOwA-kJPMP9M40ptuL84_0,1412
240
- runtimepy/net/tcp/http/__init__.py,sha256=0nEB6KFqV9GxMwFKqKIswA0wihHfbLP5UD-r5ulgTj0,6391
240
+ runtimepy/net/tcp/http/__init__.py,sha256=7Pnge4d50hG6QjcTXb1lZW1Xcver-vLVubBhj-WUduQ,6369
241
241
  runtimepy/net/tcp/scpi/__init__.py,sha256=FcNouVQh0A27-x16lzTbt7vZfWs4bRU9uZqbeVjDfiU,2173
242
242
  runtimepy/net/tcp/telnet/__init__.py,sha256=2pGaG-IlZA29BM6QAvI4q9w484fgvypX4fOIioDem94,4814
243
243
  runtimepy/net/tcp/telnet/codes.py,sha256=1-yyRe-Kz_W7d6B0P3iT1AaSNR3_Twmn-MUjKCJJknY,3518
@@ -253,7 +253,7 @@ runtimepy/net/udp/tftp/endpoint.py,sha256=so60LdPTG66N5tdhHhiX7j_TBHvNOTi4JIgLcg
253
253
  runtimepy/net/udp/tftp/enums.py,sha256=06juMd__pJZsyL8zO8p3hRucnOratt1qtz9zcxzMg4s,1579
254
254
  runtimepy/net/udp/tftp/io.py,sha256=w6cnUt-T-Ma6Vg8BWoRbsNnIWUv0HTY4am6bcLWxNJs,803
255
255
  runtimepy/net/websocket/__init__.py,sha256=YjSmoxiigmsI_hcQw6nueX7bxhrRGerEERnPvgLVEVA,313
256
- runtimepy/net/websocket/connection.py,sha256=THrqy_WmwFuiNkojQ6pTUhBTJdokvWbH-3DsB96zCLU,10370
256
+ runtimepy/net/websocket/connection.py,sha256=a6SNp-HW6o4ZJtvzx97mWSeK_eTTv_EB2FAsymON09g,10331
257
257
  runtimepy/noise/__init__.py,sha256=EJM7h3t_z74wwrn6FAFQwYE2yUcOZQ1K1IQqOb8Z0AI,384
258
258
  runtimepy/primitives/__init__.py,sha256=g5IK6e_UZuGhj9QNYoCn5TbhNatWX0nEYUs-JzsOizQ,2618
259
259
  runtimepy/primitives/base.py,sha256=6N_mfTuv0RJJYofSQQ858vJfgcTvjjvfXeebMw_1bw8,9339
@@ -311,9 +311,9 @@ runtimepy/tui/channels/__init__.py,sha256=evDaiIn-YS9uGhdo8ZGtP9VK1ek6sr_P1nJ9Ju
311
311
  runtimepy/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
312
312
  runtimepy/ui/button.py,sha256=8MXnhqmVvANwbbTA8gu3b8N4IIvRYicnwxFQD6SZy3U,2045
313
313
  runtimepy/ui/controls.py,sha256=L55Af-4vGq6ZHewdoA7C_mAYq35WXl8NzOdcsmQIo7M,1868
314
- runtimepy-5.15.7.dist-info/licenses/LICENSE,sha256=yKBRwbO-cOPBrlpsZmJkkSa33DfY31aE8t7lZ0DwlUo,1071
315
- runtimepy-5.15.7.dist-info/METADATA,sha256=sZIDlVdKnti18Hr1tMV7HOmFlKoh-PF2XQPC942dRPM,9268
316
- runtimepy-5.15.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
317
- runtimepy-5.15.7.dist-info/entry_points.txt,sha256=-btVBkYv7ybcopqZ_pRky-bEzu3vhbaG3W3Z7ERBiFE,51
318
- runtimepy-5.15.7.dist-info/top_level.txt,sha256=0jPmh6yqHyyJJDwEID-LpQly-9kQ3WRMjH7Lix8peLg,10
319
- runtimepy-5.15.7.dist-info/RECORD,,
314
+ runtimepy-5.16.0.dist-info/licenses/LICENSE,sha256=yKBRwbO-cOPBrlpsZmJkkSa33DfY31aE8t7lZ0DwlUo,1071
315
+ runtimepy-5.16.0.dist-info/METADATA,sha256=wIbK_eIILzPTBu9b-_lNgxbAstvYANApLefug7WUodI,9220
316
+ runtimepy-5.16.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
317
+ runtimepy-5.16.0.dist-info/entry_points.txt,sha256=-btVBkYv7ybcopqZ_pRky-bEzu3vhbaG3W3Z7ERBiFE,51
318
+ runtimepy-5.16.0.dist-info/top_level.txt,sha256=0jPmh6yqHyyJJDwEID-LpQly-9kQ3WRMjH7Lix8peLg,10
319
+ runtimepy-5.16.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5