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 +2 -2
- runtimepy/codec/protocol/receiver.py +7 -1
- runtimepy/commands/arbiter.py +3 -4
- runtimepy/data/css/main.css +2 -0
- runtimepy/message/interface.py +5 -1
- runtimepy/net/arbiter/base.py +13 -4
- runtimepy/net/arbiter/info.py +13 -6
- runtimepy/net/connection.py +2 -1
- runtimepy/net/http/response.py +18 -4
- runtimepy/net/server/__init__.py +15 -3
- runtimepy/net/tcp/http/__init__.py +5 -5
- runtimepy/net/websocket/connection.py +1 -3
- {runtimepy-5.15.7.dist-info → runtimepy-5.16.0.dist-info}/METADATA +19 -20
- {runtimepy-5.15.7.dist-info → runtimepy-5.16.0.dist-info}/RECORD +18 -18
- {runtimepy-5.15.7.dist-info → runtimepy-5.16.0.dist-info}/WHEEL +1 -1
- {runtimepy-5.15.7.dist-info → runtimepy-5.16.0.dist-info}/entry_points.txt +0 -0
- {runtimepy-5.15.7.dist-info → runtimepy-5.16.0.dist-info}/licenses/LICENSE +0 -0
- {runtimepy-5.15.7.dist-info → runtimepy-5.16.0.dist-info}/top_level.txt +0 -0
runtimepy/__init__.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# =====================================
|
|
2
2
|
# generator=datazen
|
|
3
3
|
# version=3.2.3
|
|
4
|
-
# hash=
|
|
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.
|
|
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(
|
|
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
|
runtimepy/commands/arbiter.py
CHANGED
|
@@ -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
|
-
|
|
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),
|
runtimepy/data/css/main.css
CHANGED
runtimepy/message/interface.py
CHANGED
|
@@ -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
|
-
|
|
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(
|
runtimepy/net/arbiter/base.py
CHANGED
|
@@ -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
|
-
|
|
241
|
-
|
|
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,
|
|
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.
|
runtimepy/net/arbiter/info.py
CHANGED
|
@@ -69,7 +69,10 @@ class RuntimeStruct(RuntimeStructBase):
|
|
|
69
69
|
final_poll = False
|
|
70
70
|
|
|
71
71
|
def init_env(self) -> None:
|
|
72
|
-
"""Initialize this
|
|
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
|
-
|
|
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:
|
runtimepy/net/connection.py
CHANGED
|
@@ -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()
|
runtimepy/net/http/response.py
CHANGED
|
@@ -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 =
|
|
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
|
|
runtimepy/net/server/__init__.py
CHANGED
|
@@ -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
|
|
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 =
|
|
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
|
-
|
|
177
|
-
header["content-length"] = "0"
|
|
178
|
-
|
|
176
|
+
size = None
|
|
179
177
|
if isinstance(data, AsyncResponse):
|
|
180
|
-
|
|
178
|
+
size = await data.size()
|
|
181
179
|
elif data is not None:
|
|
182
|
-
|
|
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.
|
|
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=
|
|
54
|
+
hash=ebb0bba9899d4baf7ce73b082f5e384e
|
|
55
55
|
=====================================
|
|
56
56
|
-->
|
|
57
57
|
|
|
58
|
-
# runtimepy ([5.
|
|
58
|
+
# runtimepy ([5.16.0](https://pypi.org/project/runtimepy/))
|
|
59
59
|
|
|
60
60
|
[](https://pypi.org/project/runtimepy/)
|
|
61
61
|

|
|
@@ -89,7 +89,7 @@ This package is tested on the following platforms:
|
|
|
89
89
|
# Command-line Options
|
|
90
90
|
|
|
91
91
|
```
|
|
92
|
-
$ ./venv3.
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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
|
|
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.
|
|
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
|
|
242
|
-
-m
|
|
243
|
-
-t
|
|
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
|
|
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.
|
|
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
|
|
258
|
+
-i, --iterations ITERATIONS
|
|
260
259
|
maximum number of program iterations (if greater than
|
|
261
260
|
zero, default: 0)
|
|
262
|
-
-r
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
175
|
-
runtimepy/net/arbiter/info.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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.
|
|
315
|
-
runtimepy-5.
|
|
316
|
-
runtimepy-5.
|
|
317
|
-
runtimepy-5.
|
|
318
|
-
runtimepy-5.
|
|
319
|
-
runtimepy-5.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|