runtimepy 5.10.1__py3-none-any.whl → 5.11.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/channel/environment/array.py +4 -4
- runtimepy/channel/environment/telemetry.py +3 -3
- runtimepy/channel/event/__init__.py +1 -1
- runtimepy/codec/protocol/__init__.py +3 -2
- runtimepy/codec/protocol/base.py +97 -54
- runtimepy/codec/protocol/json.py +18 -13
- runtimepy/codec/system/__init__.py +2 -3
- runtimepy/data/favicon.ico +0 -0
- runtimepy/data/static/svg/chip-circle-bootstrap.svg +1 -1
- runtimepy/net/server/__init__.py +24 -3
- runtimepy/net/server/markdown.py +53 -0
- runtimepy/net/udp/tftp/__init__.py +0 -1
- runtimepy/primitives/array/__init__.py +28 -9
- runtimepy/primitives/bool.py +13 -6
- runtimepy/primitives/float.py +5 -0
- runtimepy/primitives/int.py +7 -0
- runtimepy/primitives/serializable/__init__.py +1 -1
- runtimepy/primitives/serializable/base.py +47 -19
- runtimepy/primitives/types/bounds.py +5 -0
- {runtimepy-5.10.1.dist-info → runtimepy-5.11.0.dist-info}/METADATA +6 -5
- {runtimepy-5.10.1.dist-info → runtimepy-5.11.0.dist-info}/RECORD +26 -25
- {runtimepy-5.10.1.dist-info → runtimepy-5.11.0.dist-info}/WHEEL +1 -1
- {runtimepy-5.10.1.dist-info → runtimepy-5.11.0.dist-info}/entry_points.txt +0 -0
- {runtimepy-5.10.1.dist-info → runtimepy-5.11.0.dist-info/licenses}/LICENSE +0 -0
- {runtimepy-5.10.1.dist-info → runtimepy-5.11.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.1.4
|
|
4
|
-
# hash=
|
|
4
|
+
# hash=c4e165f8c6309dd6819689f0262cf92d
|
|
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.11.0"
|
|
14
14
|
|
|
15
15
|
# runtimepy-specific content.
|
|
16
16
|
METRICS_NAME = "metrics"
|
|
@@ -95,10 +95,10 @@ class ArrayChannelEnvironment(_BaseChannelEnvironment):
|
|
|
95
95
|
|
|
96
96
|
# Begin handling a new bit-fields primitive.
|
|
97
97
|
if curr_fields is None:
|
|
98
|
-
|
|
99
|
-
assert
|
|
100
|
-
result.array.add(
|
|
101
|
-
available_field_names = set(
|
|
98
|
+
curr_fields = self.fields.get_fields(name)
|
|
99
|
+
assert curr_fields is not None, f"Unknown bit-field '{name}'!"
|
|
100
|
+
result.array.add(curr_fields.raw)
|
|
101
|
+
available_field_names = set(curr_fields.names)
|
|
102
102
|
|
|
103
103
|
# Keep track of field names processed in the current bit-fields
|
|
104
104
|
# primitive.
|
|
@@ -99,7 +99,7 @@ class TelemetryChannelEnvironment(_BaseChannelEnvironment):
|
|
|
99
99
|
cast(int, channels.event_header["timestamp"]),
|
|
100
100
|
kind.decode(
|
|
101
101
|
data,
|
|
102
|
-
byte_order=channels.event_header.
|
|
102
|
+
byte_order=channels.event_header.byte_order,
|
|
103
103
|
),
|
|
104
104
|
)
|
|
105
105
|
|
|
@@ -120,7 +120,7 @@ class TelemetryChannelEnvironment(_BaseChannelEnvironment):
|
|
|
120
120
|
cast(int, self.channels.event_header["timestamp"]),
|
|
121
121
|
kind.decode(
|
|
122
122
|
data,
|
|
123
|
-
byte_order=self.channels.event_header.
|
|
123
|
+
byte_order=self.channels.event_header.byte_order,
|
|
124
124
|
),
|
|
125
125
|
)
|
|
126
126
|
|
|
@@ -146,7 +146,7 @@ class TelemetryChannelEnvironment(_BaseChannelEnvironment):
|
|
|
146
146
|
read_size = channels.event_header.size
|
|
147
147
|
data = channels.event_fifo.pop(read_size)
|
|
148
148
|
if data is not None:
|
|
149
|
-
channels.event_header.
|
|
149
|
+
channels.event_header.update(data)
|
|
150
150
|
|
|
151
151
|
# Update local variables.
|
|
152
152
|
ident = cast(int, channels.event_header["identifier"])
|
|
@@ -90,7 +90,7 @@ class PrimitiveEvent:
|
|
|
90
90
|
self.header["timestamp"] = curr_ns
|
|
91
91
|
|
|
92
92
|
# Write header then value.
|
|
93
|
-
array = self.header
|
|
93
|
+
array = self.header
|
|
94
94
|
written += array.to_stream(stream)
|
|
95
95
|
written += raw.to_stream(stream, byte_order=array.byte_order)
|
|
96
96
|
if flush:
|
|
@@ -4,7 +4,6 @@ A module implementing an interface to build communication protocols.
|
|
|
4
4
|
|
|
5
5
|
# built-in
|
|
6
6
|
from abc import ABC, abstractmethod
|
|
7
|
-
from copy import copy
|
|
8
7
|
from typing import Optional
|
|
9
8
|
|
|
10
9
|
# internal
|
|
@@ -40,10 +39,12 @@ class ProtocolFactory(ABC):
|
|
|
40
39
|
|
|
41
40
|
# We only need to run the routine that populates the protocol once.
|
|
42
41
|
if not cls.initialized:
|
|
42
|
+
if not cls.protocol.alias:
|
|
43
|
+
cls.protocol.alias = cls.__name__
|
|
43
44
|
cls.initialize(cls.protocol)
|
|
44
45
|
cls.initialized = True
|
|
45
46
|
|
|
46
|
-
return
|
|
47
|
+
return cls.protocol.copy()
|
|
47
48
|
|
|
48
49
|
@classmethod
|
|
49
50
|
def singleton(cls) -> Protocol:
|
runtimepy/codec/protocol/base.py
CHANGED
|
@@ -3,8 +3,9 @@ A module implementing an interface to build communication protocols.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
# built-in
|
|
6
|
-
from contextlib import contextmanager
|
|
6
|
+
from contextlib import contextmanager, suppress
|
|
7
7
|
from copy import copy as _copy
|
|
8
|
+
from io import StringIO
|
|
8
9
|
from typing import Iterator as _Iterator
|
|
9
10
|
from typing import NamedTuple
|
|
10
11
|
from typing import Optional as _Optional
|
|
@@ -57,9 +58,10 @@ class FieldSpec(NamedTuple):
|
|
|
57
58
|
|
|
58
59
|
|
|
59
60
|
T = _TypeVar("T", bound="ProtocolBase")
|
|
61
|
+
ProtocolBuild = list[_Union[int, FieldSpec, tuple[str, int]]]
|
|
60
62
|
|
|
61
63
|
|
|
62
|
-
class ProtocolBase:
|
|
64
|
+
class ProtocolBase(PrimitiveArray):
|
|
63
65
|
"""A class for defining runtime communication protocols."""
|
|
64
66
|
|
|
65
67
|
def __init__(
|
|
@@ -67,14 +69,16 @@ class ProtocolBase:
|
|
|
67
69
|
enum_registry: _EnumRegistry,
|
|
68
70
|
names: _NameRegistry = None,
|
|
69
71
|
fields: BitFieldsManager = None,
|
|
70
|
-
build:
|
|
72
|
+
build: ProtocolBuild = None,
|
|
71
73
|
identifier: int = 1,
|
|
72
74
|
byte_order: _Union[_ByteOrder, _RegistryKey] = _DEFAULT_BYTE_ORDER,
|
|
73
75
|
serializables: SerializableMap = None,
|
|
76
|
+
alias: str = None,
|
|
74
77
|
) -> None:
|
|
75
78
|
"""Initialize this protocol."""
|
|
76
79
|
|
|
77
80
|
self.id = identifier
|
|
81
|
+
self.alias = alias
|
|
78
82
|
|
|
79
83
|
# Register the byte-order enumeration if it's not present.
|
|
80
84
|
self._enum_registry = enum_registry
|
|
@@ -86,7 +90,8 @@ class ProtocolBase:
|
|
|
86
90
|
byte_order = _ByteOrder(
|
|
87
91
|
self._enum_registry["ByteOrder"].get_int(byte_order)
|
|
88
92
|
)
|
|
89
|
-
|
|
93
|
+
|
|
94
|
+
super().__init__(byte_order=byte_order)
|
|
90
95
|
|
|
91
96
|
if names is None:
|
|
92
97
|
names = _NameRegistry()
|
|
@@ -96,11 +101,11 @@ class ProtocolBase:
|
|
|
96
101
|
fields = BitFieldsManager(self.names, self._enum_registry)
|
|
97
102
|
self._fields = fields
|
|
98
103
|
|
|
99
|
-
self._regular_fields: dict[str, _AnyPrimitive] = {}
|
|
104
|
+
self._regular_fields: dict[str, list[_AnyPrimitive]] = {}
|
|
100
105
|
self._enum_fields: dict[str, _RuntimeEnum] = {}
|
|
101
106
|
|
|
102
107
|
# Keep track of the order that the protocol was created.
|
|
103
|
-
self._build:
|
|
108
|
+
self._build: ProtocolBuild = []
|
|
104
109
|
|
|
105
110
|
# Keep track of named serializables.
|
|
106
111
|
self.serializables: SerializableMap = {}
|
|
@@ -110,24 +115,28 @@ class ProtocolBase:
|
|
|
110
115
|
build = []
|
|
111
116
|
for item in build:
|
|
112
117
|
if isinstance(item, int):
|
|
113
|
-
self._add_bit_fields(self._fields.fields[item]
|
|
114
|
-
elif isinstance(item,
|
|
115
|
-
assert serializables, (item, serializables)
|
|
116
|
-
self.add_field(item, serializable=serializables[item])
|
|
117
|
-
del serializables[item]
|
|
118
|
-
else:
|
|
118
|
+
self._add_bit_fields(self._fields.fields[item])
|
|
119
|
+
elif isinstance(item, FieldSpec):
|
|
119
120
|
self.add_field(
|
|
120
121
|
item.name,
|
|
121
122
|
item.kind,
|
|
122
123
|
enum=item.enum,
|
|
123
|
-
track=False,
|
|
124
124
|
array_length=item.array_length,
|
|
125
125
|
)
|
|
126
|
+
else:
|
|
127
|
+
assert serializables, (item, serializables)
|
|
128
|
+
name = item[0]
|
|
129
|
+
self.add_serializable(
|
|
130
|
+
name,
|
|
131
|
+
serializables[name][0],
|
|
132
|
+
array_length=None if item[1] == 1 else item[1],
|
|
133
|
+
)
|
|
134
|
+
del serializables[name]
|
|
126
135
|
|
|
127
136
|
# Ensure all serializables were handled via build.
|
|
128
137
|
assert not serializables, serializables
|
|
129
138
|
|
|
130
|
-
def
|
|
139
|
+
def _copy_impl(self: T) -> T:
|
|
131
140
|
"""Create another protocol instance from this one."""
|
|
132
141
|
|
|
133
142
|
return self.__class__(
|
|
@@ -135,11 +144,12 @@ class ProtocolBase:
|
|
|
135
144
|
names=self.names,
|
|
136
145
|
fields=_copy(self._fields),
|
|
137
146
|
build=self._build,
|
|
138
|
-
byte_order=self.
|
|
147
|
+
byte_order=self.byte_order,
|
|
139
148
|
serializables={
|
|
140
|
-
key: val.copy_without_chain()
|
|
149
|
+
key: [val[0].copy_without_chain()]
|
|
141
150
|
for key, val in self.serializables.items()
|
|
142
151
|
},
|
|
152
|
+
alias=self.alias,
|
|
143
153
|
)
|
|
144
154
|
|
|
145
155
|
def register_name(self, name: str) -> int:
|
|
@@ -151,13 +161,14 @@ class ProtocolBase:
|
|
|
151
161
|
|
|
152
162
|
def add_serializable(
|
|
153
163
|
self, name: str, serializable: Serializable, array_length: int = None
|
|
154
|
-
) ->
|
|
164
|
+
) -> None:
|
|
155
165
|
"""Add a serializable instance."""
|
|
156
166
|
|
|
157
167
|
self.register_name(name)
|
|
158
|
-
|
|
159
|
-
self.
|
|
160
|
-
|
|
168
|
+
|
|
169
|
+
instances = self.add_to_end(serializable, array_length=array_length)
|
|
170
|
+
self._build.append((name, len(instances)))
|
|
171
|
+
self.serializables[name] = instances
|
|
161
172
|
|
|
162
173
|
def add_field(
|
|
163
174
|
self,
|
|
@@ -165,17 +176,17 @@ class ProtocolBase:
|
|
|
165
176
|
kind: _Primitivelike = None,
|
|
166
177
|
enum: _RegistryKey = None,
|
|
167
178
|
serializable: Serializable = None,
|
|
168
|
-
track: bool = True,
|
|
169
179
|
array_length: int = None,
|
|
170
|
-
) ->
|
|
180
|
+
) -> None:
|
|
171
181
|
"""Add a new field to the protocol."""
|
|
172
182
|
|
|
173
183
|
# Add the serializable to the end of this protocol.
|
|
174
184
|
if serializable is not None:
|
|
175
185
|
assert kind is None and enum is None
|
|
176
|
-
|
|
186
|
+
self.add_serializable(
|
|
177
187
|
name, serializable, array_length=array_length
|
|
178
188
|
)
|
|
189
|
+
return
|
|
179
190
|
|
|
180
191
|
self.register_name(name)
|
|
181
192
|
|
|
@@ -189,25 +200,20 @@ class ProtocolBase:
|
|
|
189
200
|
kind = runtime_enum.primitive
|
|
190
201
|
|
|
191
202
|
assert kind is not None
|
|
192
|
-
new = _create(kind)
|
|
193
|
-
|
|
194
|
-
result = self.array.add(new, array_length=array_length)
|
|
195
|
-
self._regular_fields[name] = new
|
|
196
203
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
)
|
|
204
|
+
self._regular_fields[name] = self.add(
|
|
205
|
+
_create(kind), array_length=array_length
|
|
206
|
+
)
|
|
201
207
|
|
|
202
|
-
|
|
208
|
+
self._build.append(
|
|
209
|
+
FieldSpec(name, kind, enum, array_length=array_length)
|
|
210
|
+
)
|
|
203
211
|
|
|
204
|
-
def _add_bit_fields(self, fields: _BitFields
|
|
212
|
+
def _add_bit_fields(self, fields: _BitFields) -> None:
|
|
205
213
|
"""Add a bit-fields instance."""
|
|
206
214
|
|
|
207
|
-
|
|
208
|
-
self.
|
|
209
|
-
if track:
|
|
210
|
-
self._build.append(idx)
|
|
215
|
+
self._build.append(self._fields.add(fields))
|
|
216
|
+
self.add(fields.raw)
|
|
211
217
|
|
|
212
218
|
@contextmanager
|
|
213
219
|
def add_bit_fields(
|
|
@@ -219,55 +225,92 @@ class ProtocolBase:
|
|
|
219
225
|
yield new
|
|
220
226
|
self._add_bit_fields(new)
|
|
221
227
|
|
|
222
|
-
def value(
|
|
228
|
+
def value(
|
|
229
|
+
self, name: str, resolve_enum: bool = True, index: int = 0
|
|
230
|
+
) -> ProtocolPrimitive:
|
|
223
231
|
"""Get the value of a field belonging to the protocol."""
|
|
224
232
|
|
|
225
233
|
val: ProtocolPrimitive = 0
|
|
226
234
|
|
|
227
235
|
if name in self._regular_fields:
|
|
228
|
-
val = self._regular_fields[name].value
|
|
236
|
+
val = self._regular_fields[name][index].value
|
|
229
237
|
|
|
230
238
|
# Resolve the enum value.
|
|
231
239
|
if resolve_enum and name in self._enum_fields:
|
|
232
|
-
|
|
240
|
+
with suppress(KeyError):
|
|
241
|
+
val = self._enum_fields[name].get_str(val) # type: ignore
|
|
233
242
|
|
|
234
243
|
return val
|
|
235
244
|
|
|
236
245
|
return self._fields.get(name, resolve_enum=resolve_enum)
|
|
237
246
|
|
|
238
|
-
@property
|
|
239
|
-
def size(self) -> int:
|
|
240
|
-
"""Get this protocol's size in bytes."""
|
|
241
|
-
return self.array.length()
|
|
242
|
-
|
|
243
247
|
def trace_size(self, logger: LoggerType) -> None:
|
|
244
248
|
"""Log a size trace."""
|
|
245
|
-
logger.info("%s: %s", self, self.
|
|
249
|
+
logger.info("%s: %s", self, self.length_trace(alias=self.alias))
|
|
246
250
|
|
|
247
251
|
def __str__(self) -> str:
|
|
248
252
|
"""Get this instance as a string."""
|
|
249
253
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
254
|
+
with StringIO() as stream:
|
|
255
|
+
stream.write(
|
|
256
|
+
"{"
|
|
257
|
+
+ f"{self.resolve_alias(alias=self.alias)}({self.length()}): "
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
parts = []
|
|
261
|
+
for name in self.names.registered_order:
|
|
262
|
+
part = name
|
|
263
|
+
count = 1
|
|
264
|
+
|
|
265
|
+
if name in self.serializables:
|
|
266
|
+
count = len(self.serializables[name])
|
|
267
|
+
part += f"<{self.serializables[name][0].resolve_alias()}>"
|
|
268
|
+
elif name in self._regular_fields:
|
|
269
|
+
count = len(self._regular_fields[name])
|
|
270
|
+
|
|
271
|
+
part += f"<{self._regular_fields[name][0].kind}>"
|
|
272
|
+
|
|
273
|
+
if count > 1:
|
|
274
|
+
part += f"[{count}] = ["
|
|
275
|
+
if name in self._regular_fields:
|
|
276
|
+
part += ", ".join(
|
|
277
|
+
str(x.value) for x in self._regular_fields[name]
|
|
278
|
+
)
|
|
279
|
+
else:
|
|
280
|
+
part += ", ".join("..." for _ in range(count))
|
|
281
|
+
part += "]"
|
|
282
|
+
else:
|
|
283
|
+
part += f" = {self[name]}"
|
|
284
|
+
|
|
285
|
+
parts.append(part)
|
|
253
286
|
|
|
254
|
-
|
|
287
|
+
stream.write(", ".join(parts))
|
|
288
|
+
|
|
289
|
+
stream.write("}")
|
|
290
|
+
|
|
291
|
+
return stream.getvalue()
|
|
292
|
+
|
|
293
|
+
def __getitem__(self, name: str) -> ProtocolPrimitive: # type: ignore
|
|
255
294
|
"""Get the value of a protocol field."""
|
|
256
295
|
|
|
257
296
|
if name in self.serializables:
|
|
258
|
-
return str(self.serializables[name])
|
|
297
|
+
return str(self.serializables[name][0])
|
|
259
298
|
|
|
260
299
|
return self.value(name)
|
|
261
300
|
|
|
262
|
-
def
|
|
301
|
+
def set(self, name: str, val: ProtocolPrimitive, index: int = 0) -> None:
|
|
263
302
|
"""Set a value of a field belonging to the protocol."""
|
|
264
303
|
|
|
265
304
|
if name in self._regular_fields:
|
|
266
305
|
# Resolve an enum value.
|
|
267
306
|
if isinstance(val, str):
|
|
268
307
|
val = self._enum_fields[name].get_int(val)
|
|
269
|
-
self._regular_fields[name].value = val
|
|
308
|
+
self._regular_fields[name][index].value = val
|
|
270
309
|
elif name in self.serializables and isinstance(val, str):
|
|
271
|
-
self.serializables[name].update_str(val)
|
|
310
|
+
self.serializables[name][index].update_str(val)
|
|
272
311
|
else:
|
|
273
312
|
self._fields.set(name, val) # type: ignore
|
|
313
|
+
|
|
314
|
+
def __setitem__(self, name: str, val: ProtocolPrimitive) -> None:
|
|
315
|
+
"""Set a value of a field belonging to the protocol."""
|
|
316
|
+
self.set(name, val)
|
runtimepy/codec/protocol/json.py
CHANGED
|
@@ -14,7 +14,11 @@ from vcorelib.io.types import JsonObject as _JsonObject
|
|
|
14
14
|
from vcorelib.io.types import JsonValue as _JsonValue
|
|
15
15
|
|
|
16
16
|
# internal
|
|
17
|
-
from runtimepy.codec.protocol.base import
|
|
17
|
+
from runtimepy.codec.protocol.base import (
|
|
18
|
+
FieldSpec,
|
|
19
|
+
ProtocolBase,
|
|
20
|
+
ProtocolBuild,
|
|
21
|
+
)
|
|
18
22
|
from runtimepy.primitives.field.manager import (
|
|
19
23
|
ENUMS_KEY,
|
|
20
24
|
NAMES_KEY,
|
|
@@ -46,9 +50,11 @@ class JsonProtocol(ProtocolBase):
|
|
|
46
50
|
"""Export this protocol's data to JSON."""
|
|
47
51
|
|
|
48
52
|
data = self._fields.export_json(resolve_enum=resolve_enum)
|
|
53
|
+
|
|
49
54
|
data[META_KEY] = {
|
|
50
55
|
"id": self.id,
|
|
51
|
-
"byte_order": self.
|
|
56
|
+
"byte_order": self.byte_order.name.lower(),
|
|
57
|
+
"alias": self.alias,
|
|
52
58
|
}
|
|
53
59
|
|
|
54
60
|
# Export regular-field names.
|
|
@@ -72,12 +78,12 @@ class JsonProtocol(ProtocolBase):
|
|
|
72
78
|
)
|
|
73
79
|
|
|
74
80
|
# Export the build specification.
|
|
75
|
-
build: list[_Union[int, _JsonObject, str]] = []
|
|
81
|
+
build: list[_Union[int, _JsonObject, str, tuple[str, int]]] = []
|
|
76
82
|
for item in self._build:
|
|
77
|
-
if isinstance(item,
|
|
78
|
-
build.append(item)
|
|
79
|
-
else:
|
|
83
|
+
if isinstance(item, FieldSpec):
|
|
80
84
|
build.append(item.asdict())
|
|
85
|
+
else:
|
|
86
|
+
build.append(item)
|
|
81
87
|
data[BUILD_KEY] = _cast(_JsonObject, build)
|
|
82
88
|
|
|
83
89
|
# Export regular-field values.
|
|
@@ -101,18 +107,16 @@ class JsonProtocol(ProtocolBase):
|
|
|
101
107
|
fields = BitFieldsManager.import_json(data)
|
|
102
108
|
|
|
103
109
|
# Create the build specification.
|
|
104
|
-
build:
|
|
110
|
+
build: ProtocolBuild = []
|
|
105
111
|
for item in data[BUILD_KEY]:
|
|
106
|
-
if isinstance(item,
|
|
107
|
-
build.append(item)
|
|
108
|
-
else:
|
|
112
|
+
if isinstance(item, dict):
|
|
109
113
|
build.append(
|
|
110
114
|
FieldSpec(
|
|
111
|
-
item["name"],
|
|
112
|
-
item["kind"], # type: ignore
|
|
113
|
-
enum=item.get("enum"), # type: ignore
|
|
115
|
+
item["name"], item["kind"], enum=item.get("enum")
|
|
114
116
|
)
|
|
115
117
|
)
|
|
118
|
+
else:
|
|
119
|
+
build.append(item) # type: ignore
|
|
116
120
|
|
|
117
121
|
result = cls(
|
|
118
122
|
fields.enums,
|
|
@@ -121,6 +125,7 @@ class JsonProtocol(ProtocolBase):
|
|
|
121
125
|
build=build,
|
|
122
126
|
identifier=_cast(int, data[META_KEY]["id"]),
|
|
123
127
|
byte_order=_cast(str, data[META_KEY]["byte_order"]),
|
|
128
|
+
alias=data[META_KEY]["alias"], # type: ignore
|
|
124
129
|
)
|
|
125
130
|
|
|
126
131
|
# Set values.
|
|
@@ -146,7 +146,7 @@ class TypeSystem(LoggerMixin):
|
|
|
146
146
|
if field_type_name in self.custom:
|
|
147
147
|
custom.add_serializable(
|
|
148
148
|
field_name,
|
|
149
|
-
self.custom[field_type_name].
|
|
149
|
+
self.custom[field_type_name].copy(),
|
|
150
150
|
array_length=array_length,
|
|
151
151
|
)
|
|
152
152
|
else:
|
|
@@ -227,8 +227,7 @@ class TypeSystem(LoggerMixin):
|
|
|
227
227
|
if found in self.primitives:
|
|
228
228
|
return self.primitives[found].size
|
|
229
229
|
|
|
230
|
-
result = self.custom[found].size
|
|
231
230
|
if trace:
|
|
232
231
|
self.custom[found].trace_size(self.logger)
|
|
233
232
|
|
|
234
|
-
return
|
|
233
|
+
return self.custom[found].length()
|
runtimepy/data/favicon.ico
CHANGED
|
Binary file
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
-
<circle r="50.0" cx="50.0" cy="50.0" style="fill: #
|
|
2
|
+
<circle r="50.0" cx="50.0" cy="50.0" style="fill: #6C757D" />
|
|
3
3
|
<rect x="16.666666666666664" y="33.333333333333336" width="16.666666666666668" height="8.333333333333334" rx="4.166666666666667" ry="4.166666666666667" style="fill: #495057" />
|
|
4
4
|
<rect x="16.666666666666664" y="45.833333333333336" width="16.666666666666668" height="8.333333333333334" rx="4.166666666666667" ry="4.166666666666667" style="fill: #495057" />
|
|
5
5
|
<rect x="16.666666666666664" y="58.333333333333336" width="16.666666666666668" height="8.333333333333334" rx="4.166666666666667" ry="4.166666666666667" style="fill: #495057" />
|
runtimepy/net/server/__init__.py
CHANGED
|
@@ -24,6 +24,7 @@ from runtimepy.net.http.request_target import PathMaybeQuery
|
|
|
24
24
|
from runtimepy.net.http.response import 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
|
+
from runtimepy.net.server.markdown import markdown_for_dir
|
|
27
28
|
from runtimepy.net.tcp.http import HttpConnection
|
|
28
29
|
from runtimepy.util import normalize_root, path_has_part, read_binary
|
|
29
30
|
|
|
@@ -177,10 +178,20 @@ class RuntimepyServerConnection(HttpConnection):
|
|
|
177
178
|
|
|
178
179
|
result = None
|
|
179
180
|
|
|
180
|
-
#
|
|
181
|
+
# Keep track of directories encountered.
|
|
182
|
+
directories: list[Path] = []
|
|
183
|
+
|
|
184
|
+
# Build a list of all candidate files to check.
|
|
185
|
+
candidates: list[Path] = []
|
|
181
186
|
for search in self.paths:
|
|
182
187
|
candidate = search.joinpath(path[0][1:])
|
|
188
|
+
if candidate.is_dir():
|
|
189
|
+
directories.append(candidate)
|
|
190
|
+
candidates.append(candidate.joinpath("index.html"))
|
|
191
|
+
else:
|
|
192
|
+
candidates.append(candidate)
|
|
183
193
|
|
|
194
|
+
for candidate in candidates:
|
|
184
195
|
# Handle markdown sources.
|
|
185
196
|
if candidate.name:
|
|
186
197
|
md_candidate = candidate.with_suffix(".md")
|
|
@@ -189,6 +200,7 @@ class RuntimepyServerConnection(HttpConnection):
|
|
|
189
200
|
md_candidate, response, path[1]
|
|
190
201
|
)
|
|
191
202
|
|
|
203
|
+
# Handle files.
|
|
192
204
|
if candidate.is_file():
|
|
193
205
|
mime, encoding = mimetypes.guess_type(candidate, strict=False)
|
|
194
206
|
|
|
@@ -203,9 +215,18 @@ class RuntimepyServerConnection(HttpConnection):
|
|
|
203
215
|
|
|
204
216
|
# Return the file data.
|
|
205
217
|
result = await read_binary(candidate)
|
|
206
|
-
|
|
207
218
|
break
|
|
208
219
|
|
|
220
|
+
# Handle a directory as a last resort.
|
|
221
|
+
if not result and directories:
|
|
222
|
+
result = self.render_markdown(
|
|
223
|
+
markdown_for_dir(
|
|
224
|
+
directories[0], {"applications": self.apps.keys()}
|
|
225
|
+
),
|
|
226
|
+
response,
|
|
227
|
+
path[1],
|
|
228
|
+
)
|
|
229
|
+
|
|
209
230
|
return result
|
|
210
231
|
|
|
211
232
|
def handle_command(
|
|
@@ -278,7 +299,7 @@ class RuntimepyServerConnection(HttpConnection):
|
|
|
278
299
|
return self.favicon_data
|
|
279
300
|
|
|
280
301
|
# Try serving a file and handling redirects.
|
|
281
|
-
for handler in [self.
|
|
302
|
+
for handler in [self.try_redirect, self.try_file]:
|
|
282
303
|
result = await handler(
|
|
283
304
|
request.target.origin_form, response
|
|
284
305
|
)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A module implementing web server markdown interfaces.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
# built-in
|
|
6
|
+
from io import StringIO
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Iterable, cast
|
|
9
|
+
|
|
10
|
+
# third-party
|
|
11
|
+
from vcorelib.io.file_writer import IndentedFileWriter
|
|
12
|
+
from vcorelib.paths import rel
|
|
13
|
+
|
|
14
|
+
LOGO_MARKDOWN = (
|
|
15
|
+
"[](https://libre-embedded.com)"
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def markdown_for_dir(
|
|
21
|
+
path: Path, extra_links: dict[str, Iterable[str]] = None
|
|
22
|
+
) -> str:
|
|
23
|
+
"""Get markdown data for a directory."""
|
|
24
|
+
|
|
25
|
+
with IndentedFileWriter.string() as writer:
|
|
26
|
+
writer.write(f"# Directory {LOGO_MARKDOWN} Viewer")
|
|
27
|
+
with writer.padding():
|
|
28
|
+
writer.write("---")
|
|
29
|
+
|
|
30
|
+
if extra_links:
|
|
31
|
+
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}`")
|
|
38
|
+
writer.empty()
|
|
39
|
+
|
|
40
|
+
writer.write("* [..](..)")
|
|
41
|
+
|
|
42
|
+
for item in path.iterdir():
|
|
43
|
+
curr = rel(item, base=path)
|
|
44
|
+
|
|
45
|
+
name = f"`{curr}`"
|
|
46
|
+
if item.is_dir():
|
|
47
|
+
name = f"**{name}**"
|
|
48
|
+
|
|
49
|
+
writer.write(f"* [{name}]({curr})")
|
|
50
|
+
|
|
51
|
+
result: str = cast(StringIO, writer.stream).getvalue()
|
|
52
|
+
|
|
53
|
+
return result
|
|
@@ -180,44 +180,50 @@ class PrimitiveArray(Serializable):
|
|
|
180
180
|
|
|
181
181
|
def add_primitive(
|
|
182
182
|
self, kind: _Primitivelike, array_length: int = None
|
|
183
|
-
) ->
|
|
183
|
+
) -> list[_AnyPrimitive]:
|
|
184
184
|
"""Add to the array by specifying the type of element to add."""
|
|
185
|
+
|
|
185
186
|
return self.add(_create(kind), array_length=array_length)
|
|
186
187
|
|
|
187
|
-
def add(
|
|
188
|
+
def add(
|
|
189
|
+
self, primitive: _AnyPrimitive, array_length: int = None
|
|
190
|
+
) -> list[_AnyPrimitive]:
|
|
188
191
|
"""Add another primitive to manage."""
|
|
189
192
|
|
|
193
|
+
result = []
|
|
194
|
+
|
|
190
195
|
end = self.end
|
|
191
196
|
if isinstance(end, PrimitiveArray):
|
|
192
197
|
if end is self:
|
|
193
198
|
self._primitives.append(primitive)
|
|
194
199
|
self._format += primitive.kind.format
|
|
195
200
|
self.size += primitive.size
|
|
201
|
+
result.append(primitive)
|
|
196
202
|
|
|
197
203
|
# Handle array length.
|
|
198
204
|
if array_length is not None:
|
|
199
205
|
for _ in range(array_length - 1):
|
|
206
|
+
inst = primitive.copy()
|
|
200
207
|
self._primitives.append(
|
|
201
|
-
|
|
208
|
+
inst, # type: ignore
|
|
202
209
|
)
|
|
203
|
-
self._format +=
|
|
204
|
-
self.size +=
|
|
210
|
+
self._format += inst.kind.format
|
|
211
|
+
self.size += inst.size
|
|
212
|
+
result.append(inst) # type: ignore
|
|
205
213
|
|
|
206
214
|
# Add tracking information for the current tail.
|
|
207
215
|
curr_idx = len(self._primitives)
|
|
208
216
|
self._bytes_to_index[self.size] = curr_idx
|
|
209
217
|
self._index_to_bytes[curr_idx] = self.size
|
|
210
|
-
result = self.size
|
|
211
218
|
else:
|
|
212
|
-
result
|
|
219
|
+
result.extend(end.add(primitive, array_length=array_length))
|
|
213
220
|
|
|
214
221
|
# Add a new primitive array to the end of this chain for this
|
|
215
222
|
# primitive.
|
|
216
223
|
else:
|
|
217
224
|
new_array = PrimitiveArray(byte_order=self.byte_order)
|
|
218
225
|
end.assign(new_array)
|
|
219
|
-
|
|
220
|
-
result = new_array.add(primitive, array_length=array_length)
|
|
226
|
+
result.extend(new_array.add(primitive, array_length=array_length))
|
|
221
227
|
|
|
222
228
|
return result
|
|
223
229
|
|
|
@@ -245,3 +251,16 @@ class PrimitiveArray(Serializable):
|
|
|
245
251
|
) -> None:
|
|
246
252
|
"""Update a fragment by index."""
|
|
247
253
|
self._fragments[index].update(data, timestamp_ns=timestamp_ns)
|
|
254
|
+
|
|
255
|
+
def randomize(self, timestamp_ns: int = None, chain: bool = True) -> None:
|
|
256
|
+
"""Randomize array contents."""
|
|
257
|
+
|
|
258
|
+
for prim in self._primitives:
|
|
259
|
+
prim.randomize(timestamp_ns=timestamp_ns)
|
|
260
|
+
|
|
261
|
+
if (
|
|
262
|
+
chain
|
|
263
|
+
and self.chain is not None
|
|
264
|
+
and isinstance(self.chain, PrimitiveArray)
|
|
265
|
+
):
|
|
266
|
+
self.chain.randomize(timestamp_ns=timestamp_ns, chain=chain)
|
runtimepy/primitives/bool.py
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
A module implementing a boolean-primitive interface.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
# built-in
|
|
6
|
+
from random import getrandbits
|
|
7
|
+
|
|
5
8
|
# internal
|
|
6
9
|
from runtimepy.primitives.base import Primitive as _Primitive
|
|
7
10
|
from runtimepy.primitives.evaluation import EvalResult, evaluate
|
|
@@ -18,17 +21,21 @@ class BooleanPrimitive(_Primitive[bool]):
|
|
|
18
21
|
"""Initialize this boolean primitive."""
|
|
19
22
|
super().__init__(value=value, **kwargs)
|
|
20
23
|
|
|
21
|
-
def
|
|
24
|
+
def randomize(self, timestamp_ns: int = None) -> None:
|
|
25
|
+
"""Set this primitive to a random integer."""
|
|
26
|
+
self.set_value(bool(getrandbits(1)), timestamp_ns=timestamp_ns)
|
|
27
|
+
|
|
28
|
+
def toggle(self, timestamp_ns: int = None) -> None:
|
|
22
29
|
"""Toggle the underlying value."""
|
|
23
|
-
self.
|
|
30
|
+
self.set_value(not self.raw.value, timestamp_ns=timestamp_ns)
|
|
24
31
|
|
|
25
|
-
def set(self) -> None:
|
|
32
|
+
def set(self, timestamp_ns: int = None) -> None:
|
|
26
33
|
"""Coerce the underlying value to true."""
|
|
27
|
-
self.
|
|
34
|
+
self.set_value(True, timestamp_ns=timestamp_ns)
|
|
28
35
|
|
|
29
|
-
def clear(self) -> None:
|
|
36
|
+
def clear(self, timestamp_ns: int = None) -> None:
|
|
30
37
|
"""Coerce the underlying value to false."""
|
|
31
|
-
self.
|
|
38
|
+
self.set_value(False, timestamp_ns=timestamp_ns)
|
|
32
39
|
|
|
33
40
|
async def wait_for_state(self, state: bool, timeout: float) -> EvalResult:
|
|
34
41
|
"""Wait for this primitive to reach a specified state."""
|
runtimepy/primitives/float.py
CHANGED
|
@@ -4,6 +4,7 @@ A module implementing a floating-point primitive interface.
|
|
|
4
4
|
|
|
5
5
|
# built-in
|
|
6
6
|
import math
|
|
7
|
+
from random import random
|
|
7
8
|
|
|
8
9
|
# internal
|
|
9
10
|
from runtimepy.primitives.evaluation import (
|
|
@@ -27,6 +28,10 @@ class BaseFloatPrimitive(PrimitiveIsCloseMixin[float]):
|
|
|
27
28
|
"""Initialize this floating-point primitive."""
|
|
28
29
|
super().__init__(value=value, scaling=scaling, **kwargs)
|
|
29
30
|
|
|
31
|
+
def randomize(self, timestamp_ns: int = None) -> None:
|
|
32
|
+
"""Set this primitive to a random integer."""
|
|
33
|
+
self.set_value(random(), timestamp_ns=timestamp_ns)
|
|
34
|
+
|
|
30
35
|
def _check_callbacks(self, curr: float, new: float) -> None:
|
|
31
36
|
"""Determine if any callbacks should be serviced."""
|
|
32
37
|
|
runtimepy/primitives/int.py
CHANGED
|
@@ -33,6 +33,13 @@ class BaseIntPrimitive(PrimitiveIsCloseMixin[int]):
|
|
|
33
33
|
|
|
34
34
|
super().__init__(value=value, scaling=scaling, **kwargs)
|
|
35
35
|
|
|
36
|
+
def randomize(self, timestamp_ns: int = None) -> None:
|
|
37
|
+
"""Set this primitive to a random integer."""
|
|
38
|
+
|
|
39
|
+
assert self.kind.int_bounds is not None
|
|
40
|
+
result = self.kind.int_bounds.random()
|
|
41
|
+
self.set_value(result, timestamp_ns=timestamp_ns)
|
|
42
|
+
|
|
36
43
|
def increment(self, amount: int = 1, timestamp_ns: int = None) -> int:
|
|
37
44
|
"""Increment this primitive by some amount and return the new value."""
|
|
38
45
|
|
|
@@ -7,5 +7,5 @@ from runtimepy.primitives.serializable.base import Serializable
|
|
|
7
7
|
from runtimepy.primitives.serializable.fixed import FixedChunk
|
|
8
8
|
from runtimepy.primitives.serializable.prefixed import PrefixedChunk
|
|
9
9
|
|
|
10
|
-
SerializableMap = dict[str, Serializable]
|
|
10
|
+
SerializableMap = dict[str, list[Serializable]]
|
|
11
11
|
__all__ = ["Serializable", "SerializableMap", "FixedChunk", "PrefixedChunk"]
|
|
@@ -5,6 +5,7 @@ A module defining a base interface fore serializable objects.
|
|
|
5
5
|
# built-in
|
|
6
6
|
from abc import ABC, abstractmethod
|
|
7
7
|
from copy import copy as _copy
|
|
8
|
+
from io import BytesIO as _BytesIO
|
|
8
9
|
from typing import BinaryIO as _BinaryIO
|
|
9
10
|
from typing import TypeVar
|
|
10
11
|
|
|
@@ -46,10 +47,17 @@ class Serializable(ABC):
|
|
|
46
47
|
result += self.chain.length()
|
|
47
48
|
return result
|
|
48
49
|
|
|
49
|
-
def
|
|
50
|
+
def resolve_alias(self, alias: str = None) -> str:
|
|
51
|
+
"""Resolve a possible alias string."""
|
|
52
|
+
|
|
53
|
+
if not alias:
|
|
54
|
+
alias = getattr(self, "alias") or self.__class__.__name__
|
|
55
|
+
return alias
|
|
56
|
+
|
|
57
|
+
def length_trace(self, alias: str = None) -> str:
|
|
50
58
|
"""Get a length-tracing string for this instance."""
|
|
51
59
|
|
|
52
|
-
current = f"{self.
|
|
60
|
+
current = f"{self.resolve_alias(alias=alias)}({self.size})"
|
|
53
61
|
if self.chain is not None:
|
|
54
62
|
current += " -> " + self.chain.length_trace()
|
|
55
63
|
return current
|
|
@@ -71,7 +79,6 @@ class Serializable(ABC):
|
|
|
71
79
|
"""A method for copying instances without chain references."""
|
|
72
80
|
|
|
73
81
|
orig = self._copy_impl()
|
|
74
|
-
assert orig.chain is None
|
|
75
82
|
orig.byte_order = self.byte_order
|
|
76
83
|
return orig
|
|
77
84
|
|
|
@@ -80,7 +87,7 @@ class Serializable(ABC):
|
|
|
80
87
|
|
|
81
88
|
result = self.copy_without_chain()
|
|
82
89
|
|
|
83
|
-
if self.chain is not None:
|
|
90
|
+
if self.chain is not None and result.chain is None:
|
|
84
91
|
result.assign(self.chain.copy())
|
|
85
92
|
|
|
86
93
|
return result
|
|
@@ -104,6 +111,27 @@ class Serializable(ABC):
|
|
|
104
111
|
|
|
105
112
|
return result
|
|
106
113
|
|
|
114
|
+
def chain_bytes(self) -> bytes:
|
|
115
|
+
"""Get the fully encoded chain."""
|
|
116
|
+
with _BytesIO() as stream:
|
|
117
|
+
self.to_stream(stream)
|
|
118
|
+
return stream.getvalue()
|
|
119
|
+
|
|
120
|
+
def __eq__(self, other) -> bool:
|
|
121
|
+
"""Equivalent if full byte chains are equal."""
|
|
122
|
+
|
|
123
|
+
result = False
|
|
124
|
+
if isinstance(other, Serializable):
|
|
125
|
+
result = self.chain_bytes() == other.chain_bytes()
|
|
126
|
+
return result
|
|
127
|
+
|
|
128
|
+
def update_with(self: T, other: T, timestamp_ns: int = None) -> int:
|
|
129
|
+
"""Update this instance from another of the same type."""
|
|
130
|
+
|
|
131
|
+
return self.update_chain(
|
|
132
|
+
other.chain_bytes(), timestamp_ns=timestamp_ns
|
|
133
|
+
)
|
|
134
|
+
|
|
107
135
|
@abstractmethod
|
|
108
136
|
def update(self, data: bytes, timestamp_ns: int = None) -> int:
|
|
109
137
|
"""Update this serializable from a bytes instance."""
|
|
@@ -130,32 +158,32 @@ class Serializable(ABC):
|
|
|
130
158
|
|
|
131
159
|
return result
|
|
132
160
|
|
|
133
|
-
def
|
|
161
|
+
def update_chain(self, data: bytes, timestamp_ns: int = None) -> int:
|
|
162
|
+
"""Update this serializable from a bytes instance."""
|
|
163
|
+
|
|
164
|
+
with _BytesIO(data) as stream:
|
|
165
|
+
return self.from_stream(stream, timestamp_ns=timestamp_ns)
|
|
166
|
+
|
|
167
|
+
def assign(self, chain: T) -> None:
|
|
134
168
|
"""Assign a next serializable."""
|
|
135
169
|
|
|
136
170
|
assert self.chain is None, self.chain
|
|
137
|
-
|
|
138
171
|
# mypy regression?
|
|
139
172
|
self.chain = chain # type: ignore
|
|
140
|
-
assert self.chain is not None
|
|
141
|
-
|
|
142
|
-
return self.chain.size
|
|
143
173
|
|
|
144
|
-
def add_to_end(self, chain: T, array_length: int = None) ->
|
|
174
|
+
def add_to_end(self, chain: T, array_length: int = None) -> list[T]:
|
|
145
175
|
"""Add a new serializable to the end of this chain."""
|
|
146
176
|
|
|
147
|
-
|
|
148
|
-
# if an array is created.
|
|
149
|
-
copy_base = None
|
|
150
|
-
if array_length is not None:
|
|
151
|
-
copy_base = chain.copy()
|
|
177
|
+
result = []
|
|
152
178
|
|
|
153
|
-
|
|
179
|
+
self.end.assign(chain)
|
|
180
|
+
result.append(chain)
|
|
154
181
|
|
|
155
182
|
# Add additional array elements as copies.
|
|
156
183
|
if array_length is not None:
|
|
157
|
-
assert copy_base is not None
|
|
158
184
|
for _ in range(array_length - 1):
|
|
159
|
-
|
|
185
|
+
inst = chain.copy()
|
|
186
|
+
self.end.assign(inst)
|
|
187
|
+
result.append(inst)
|
|
160
188
|
|
|
161
|
-
return
|
|
189
|
+
return result
|
|
@@ -4,6 +4,7 @@ bounds (based on bit width).
|
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
# built-in
|
|
7
|
+
from random import randint
|
|
7
8
|
from typing import NamedTuple
|
|
8
9
|
|
|
9
10
|
|
|
@@ -13,6 +14,10 @@ class IntegerBounds(NamedTuple):
|
|
|
13
14
|
min: int
|
|
14
15
|
max: int
|
|
15
16
|
|
|
17
|
+
def random(self) -> int:
|
|
18
|
+
"""Get a random integer."""
|
|
19
|
+
return randint(self.min, self.max)
|
|
20
|
+
|
|
16
21
|
def validate(self, val: int) -> bool:
|
|
17
22
|
"""Determine if the value is within bounds."""
|
|
18
23
|
return self.min <= val <= self.max
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: runtimepy
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.11.0
|
|
4
4
|
Summary: A framework for implementing Python services.
|
|
5
5
|
Home-page: https://github.com/vkottler/runtimepy
|
|
6
6
|
Author: Vaughn Kottler
|
|
@@ -17,9 +17,9 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
17
17
|
Requires-Python: >=3.12
|
|
18
18
|
Description-Content-Type: text/markdown
|
|
19
19
|
License-File: LICENSE
|
|
20
|
+
Requires-Dist: svgen>=0.7.4
|
|
20
21
|
Requires-Dist: websockets
|
|
21
22
|
Requires-Dist: vcorelib>=3.5.1
|
|
22
|
-
Requires-Dist: svgen>=0.7.4
|
|
23
23
|
Requires-Dist: psutil
|
|
24
24
|
Requires-Dist: aiofiles
|
|
25
25
|
Provides-Extra: test
|
|
@@ -42,6 +42,7 @@ Requires-Dist: types-setuptools; extra == "test"
|
|
|
42
42
|
Requires-Dist: uvloop; (sys_platform != "win32" and sys_platform != "cygwin") and extra == "test"
|
|
43
43
|
Dynamic: author
|
|
44
44
|
Dynamic: home-page
|
|
45
|
+
Dynamic: license-file
|
|
45
46
|
Dynamic: requires-dist
|
|
46
47
|
Dynamic: requires-python
|
|
47
48
|
|
|
@@ -49,11 +50,11 @@ Dynamic: requires-python
|
|
|
49
50
|
=====================================
|
|
50
51
|
generator=datazen
|
|
51
52
|
version=3.1.4
|
|
52
|
-
hash=
|
|
53
|
+
hash=12eb2a9d91dea3ae83e38a864f6cab4b
|
|
53
54
|
=====================================
|
|
54
55
|
-->
|
|
55
56
|
|
|
56
|
-
# runtimepy ([5.
|
|
57
|
+
# runtimepy ([5.11.0](https://pypi.org/project/runtimepy/))
|
|
57
58
|
|
|
58
59
|
[](https://pypi.org/project/runtimepy/)
|
|
59
60
|

|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
runtimepy/__init__.py,sha256=
|
|
1
|
+
runtimepy/__init__.py,sha256=_iqys5Hal_wrIAXPN1-B9DZRorvDPmYsRk12jBL_9hg,391
|
|
2
2
|
runtimepy/__main__.py,sha256=OPAed6hggoQdw-6QAR62mqLC-rCkdDhOq0wyeS2vDRI,332
|
|
3
3
|
runtimepy/app.py,sha256=sTvatbsGZ2Hdel36Si_WUbNMtg9CzsJyExr5xjIcxDE,970
|
|
4
4
|
runtimepy/dev_requirements.txt,sha256=j0dh11ztJAzfaUL0iFheGjaZj9ppDzmTkclTT8YKO8c,230
|
|
@@ -11,23 +11,23 @@ runtimepy/util.py,sha256=GuyIHVFGMS02OR6-O3LnlV3DqG5hj4-IUud0QM6WicA,1684
|
|
|
11
11
|
runtimepy/channel/__init__.py,sha256=pf0RJ5g37_FVV8xoUNgzFGuIfbZEYSBA_cQlJSDTPDo,4774
|
|
12
12
|
runtimepy/channel/registry.py,sha256=nk36qM_Bf6qK6AFR0plaZHR1PU7b4LZqbQ0feJqk4lc,4784
|
|
13
13
|
runtimepy/channel/environment/__init__.py,sha256=0Jj8g7Y4bdDvmWtzpegB9D4milGPhsZokoYxmps5zgU,1612
|
|
14
|
-
runtimepy/channel/environment/array.py,sha256=
|
|
14
|
+
runtimepy/channel/environment/array.py,sha256=f9cWaYsRXUw8qE629h6jQxbYKDpOwC2GLBo4QaMa1JM,3748
|
|
15
15
|
runtimepy/channel/environment/base.py,sha256=tpD_6OHJv1bpfXmfFCNckoNo8ATOOi-XX66NQrkSNYU,14331
|
|
16
16
|
runtimepy/channel/environment/create.py,sha256=DHjoNmzZsARjfB_CfutXQ1PDdxPETi6yQoRMhM0FbwA,5319
|
|
17
17
|
runtimepy/channel/environment/file.py,sha256=PV05KZ3-CvftbKUM8acQmawOMeGGCcMrEESEBuymykg,6949
|
|
18
18
|
runtimepy/channel/environment/sample.py,sha256=Geinp2Q_qYkzYKpUJroepv6A4JWypUnAPl57jn_r_R4,4976
|
|
19
|
-
runtimepy/channel/environment/telemetry.py,sha256=
|
|
19
|
+
runtimepy/channel/environment/telemetry.py,sha256=3A7Xcp-4eHJWz_oR1SnI6rsl4o8wiSUaiMHrnK1IaQ8,5338
|
|
20
20
|
runtimepy/channel/environment/command/__init__.py,sha256=mymqk5roA-7evUovXlD2dmWaprSzrPb_3ae6bA9oEZ0,8162
|
|
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
|
|
24
|
-
runtimepy/channel/event/__init__.py,sha256=
|
|
24
|
+
runtimepy/channel/event/__init__.py,sha256=9LCSNa1Iiwr6Q6JkwQGELDQ7rWfU_xjAMh6qM1I-ueM,2793
|
|
25
25
|
runtimepy/channel/event/header.py,sha256=eDRZgzzM5HZQ8QtV4DjyAsrAhEZyM7IfwqK6WB5ACEw,868
|
|
26
26
|
runtimepy/codec/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
27
|
-
runtimepy/codec/protocol/__init__.py,sha256=
|
|
28
|
-
runtimepy/codec/protocol/base.py,sha256
|
|
29
|
-
runtimepy/codec/protocol/json.py,sha256=
|
|
30
|
-
runtimepy/codec/system/__init__.py,sha256=
|
|
27
|
+
runtimepy/codec/protocol/__init__.py,sha256=Rg7RSKGn2UBpGMpwq1aCLUBA5h4pORdh53NfR7Cjw0U,1530
|
|
28
|
+
runtimepy/codec/protocol/base.py,sha256=NRLB1ld0oB2IED5QRkwDwYsnHFG8gKtg3T7OHJ9_VkQ,10432
|
|
29
|
+
runtimepy/codec/protocol/json.py,sha256=oiaJLCzptJ5uajnpO8EDYET8gIspZIrVuyLjLuAC5dw,4142
|
|
30
|
+
runtimepy/codec/system/__init__.py,sha256=cW_Y-hC9GgIXhFQBmNO0Lx8HdFNh-wxx1mTck14PFzw,6913
|
|
31
31
|
runtimepy/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
32
32
|
runtimepy/commands/all.py,sha256=jH2dsmkqyBFe_2ZlPFpko0UCMW3fFfJsuGIbeJFbDoQ,1619
|
|
33
33
|
runtimepy/commands/arbiter.py,sha256=CtTMRYpqCAN3vWHkkr9jqWpoF7JGNXafKIBFmkarAfc,1567
|
|
@@ -45,7 +45,7 @@ runtimepy/data/404.html,sha256=sn0Mcntzb1-AekukYZAQqz43xfmZtTWa2n2HD2ItqDM,4697
|
|
|
45
45
|
runtimepy/data/browser.yaml,sha256=oc5KEV1C1uAJ4MkhNo4hyVVfJtZvHelRNqzNvD313Ow,79
|
|
46
46
|
runtimepy/data/dummy_load.yaml,sha256=PfKRXXgZnENRMSd68eznSMTV8xanVH5JY4FmoZRPFGY,1985
|
|
47
47
|
runtimepy/data/factories.yaml,sha256=esuoouMre8w7siZfBoZKqC-5myghJ_WwOOCDIq135zg,1899
|
|
48
|
-
runtimepy/data/favicon.ico,sha256=
|
|
48
|
+
runtimepy/data/favicon.ico,sha256=boxAGaHbUjMFrOO2TZpsO0nIRC-LUgwHVQYOiG1YQnM,362870
|
|
49
49
|
runtimepy/data/sample_telemetry.yaml,sha256=OpdFurkvtWJGaNl9LMlU2rKo15AaVVr-U_hoZfsbp-Y,695
|
|
50
50
|
runtimepy/data/server.yaml,sha256=wS_Ceiu2TpkfPurpqoYoPlgzc9DAWtUd24MW7t-S5rU,97
|
|
51
51
|
runtimepy/data/server_base.yaml,sha256=R_varVgGPGV4nxWYYwKUnHC9ufINi4V92YVhxCCC5wg,875
|
|
@@ -107,7 +107,7 @@ runtimepy/data/schemas/has_factory.yaml,sha256=Rsqrxv3HEBUGxPcW6CN7QczA96iBSgtm0
|
|
|
107
107
|
runtimepy/data/schemas/has_markdown.yaml,sha256=LbnEQRYdk5KR_GgORmIOiKjRg-HF8wjhA6Dm6pSm66I,45
|
|
108
108
|
runtimepy/data/schemas/has_name.yaml,sha256=I5YkXxQRYz-1-49CLyr_NA2zVqyRVQCAsb-icTaxF4s,59
|
|
109
109
|
runtimepy/data/schemas/has_request_flag.yaml,sha256=S8ly8g-FkrCVNEizbXPqicg_hpGvtH7WRsHZAA4uhjc,66
|
|
110
|
-
runtimepy/data/static/svg/chip-circle-bootstrap.svg,sha256=
|
|
110
|
+
runtimepy/data/static/svg/chip-circle-bootstrap.svg,sha256=uwo45eymlKmV3AOQ217Etarjb0UBzJJNFLa8JgQx86Y,3124
|
|
111
111
|
runtimepy/data/static/woff2/CascadiaCode-Bold.woff2,sha256=vnrwH_YbbVnq0_aedSECg-eieky43TOK3MxtCWIc_Ug,154520
|
|
112
112
|
runtimepy/data/static/woff2/CascadiaCode-BoldItalic.woff2,sha256=OOWBMRXRJJKxEfEIlKKnT-tFqoZKqGw5hMa69t-gp1c,113236
|
|
113
113
|
runtimepy/data/static/woff2/CascadiaCode-Italic.woff2,sha256=RbBc8ehMSl_ixGWnEe7zn841xDsyxdDJTo3rkYY-bf8,111628
|
|
@@ -178,9 +178,10 @@ runtimepy/net/http/request_target.py,sha256=EE1aI5VSARw1h93jyZvP56ir5O5fjd6orYK-
|
|
|
178
178
|
runtimepy/net/http/response.py,sha256=Sup8W_A0ADNzR5olKrQsVNhsQXUwPOD-eJLlLOgYlAY,2316
|
|
179
179
|
runtimepy/net/http/state.py,sha256=qCMN8aWfCRfU9XP-cIhSOo2RqfljTjbQRCflfcy2bfY,1626
|
|
180
180
|
runtimepy/net/http/version.py,sha256=mp6rgIM7-VUVKLCA0Uw96CmBkL0ET860lDVVEewpZ7w,1098
|
|
181
|
-
runtimepy/net/server/__init__.py,sha256=
|
|
181
|
+
runtimepy/net/server/__init__.py,sha256=RojwvQgqc0rTl36rXDSiM56tVXtD15T5OkpuJanlNjY,10438
|
|
182
182
|
runtimepy/net/server/html.py,sha256=ufg0PQF_iUE7PT0n3Pn3jTcun7mspZUI6_ooblcNnvI,1217
|
|
183
183
|
runtimepy/net/server/json.py,sha256=a7vM5yfq2er4DexzFqEMnxoMGDeuywKkVH4-uNJBAik,2522
|
|
184
|
+
runtimepy/net/server/markdown.py,sha256=DFjGbvIST4HXRhtTTvXVQ9ZAwrIfVzPlcU1dW8JYya8,1381
|
|
184
185
|
runtimepy/net/server/app/__init__.py,sha256=beU67t7zoKGlO7aldjQMUwYLm9mSlc78eMQazri-otw,3012
|
|
185
186
|
runtimepy/net/server/app/base.py,sha256=HF_Qa3ufrZNaYBVnBwGi-Siv3nneqEo01j5h5pK-ZTk,1871
|
|
186
187
|
runtimepy/net/server/app/create.py,sha256=eRT8qxubht5A7149Xol3Z8rkdYd_pjNLqrlyMnXk-Zg,2660
|
|
@@ -221,7 +222,7 @@ runtimepy/net/udp/connection.py,sha256=Hv963vT9tnglpZOx4KUFuoYTBPr2rltYQWDNV3mhY
|
|
|
221
222
|
runtimepy/net/udp/create.py,sha256=84YDfJbNBlN0ZwbNpvh6Dl7ZPecbZfmpjMNRRWcvJDk,2005
|
|
222
223
|
runtimepy/net/udp/protocol.py,sha256=A4SRHf0CgcL2zDs1nAsGDqz0RxKBy1soS8wtNdS5S0I,1492
|
|
223
224
|
runtimepy/net/udp/queue.py,sha256=DF-YscxQcGbGCYQLz_l_BMaSRfraZOhRwieTEdXLMds,637
|
|
224
|
-
runtimepy/net/udp/tftp/__init__.py,sha256=
|
|
225
|
+
runtimepy/net/udp/tftp/__init__.py,sha256=lR8_bFo8ECHMQygWsmbnNpsLqmwu6818k-cjKRE57yk,8983
|
|
225
226
|
runtimepy/net/udp/tftp/base.py,sha256=vpvjitZSD8R4Ggb21eIMNIsm54VkLBbBrTgMo65gn2o,11331
|
|
226
227
|
runtimepy/net/udp/tftp/endpoint.py,sha256=so60LdPTG66N5tdhHhiX7j_TBHvNOTi4JIgLcg2MAm0,10890
|
|
227
228
|
runtimepy/net/udp/tftp/enums.py,sha256=06juMd__pJZsyL8zO8p3hRucnOratt1qtz9zcxzMg4s,1579
|
|
@@ -231,27 +232,27 @@ runtimepy/net/websocket/connection.py,sha256=BMR58bLpHuulCdbLGnmMdFJOF53wVxYcUe5
|
|
|
231
232
|
runtimepy/noise/__init__.py,sha256=EJM7h3t_z74wwrn6FAFQwYE2yUcOZQ1K1IQqOb8Z0AI,384
|
|
232
233
|
runtimepy/primitives/__init__.py,sha256=nwWJH1e0KN2NsVwQ3wvRtUpl9s9Ap8Q32NNZLGol0wU,2323
|
|
233
234
|
runtimepy/primitives/base.py,sha256=BaGPUTeVMnLnTPcpjqnS2lzPN74Pe5C0XaQdgrTfW7A,9185
|
|
234
|
-
runtimepy/primitives/bool.py,sha256=
|
|
235
|
+
runtimepy/primitives/bool.py,sha256=lATPgb1e62rjLn5XlJX8lP3tVYR3DlxV8RT9HpOMdT0,1640
|
|
235
236
|
runtimepy/primitives/byte_order.py,sha256=80mMk1Sj_l49XvAtvrPmoYFpFYSM1HgYuwR2-P7os3Q,767
|
|
236
237
|
runtimepy/primitives/evaluation.py,sha256=0N7mT8uoiJaY-coF2PeEXU2WO-FmbyN2Io9_EaghO9Q,4657
|
|
237
|
-
runtimepy/primitives/float.py,sha256=
|
|
238
|
-
runtimepy/primitives/int.py,sha256=
|
|
238
|
+
runtimepy/primitives/float.py,sha256=6vzNKnnLzzM4vP10V4E0PHZQH6vTvIl34pId1oFtlqc,2146
|
|
239
|
+
runtimepy/primitives/int.py,sha256=zaZZjVSuDtZsOWRYt8eN38pPVGZfj7y4IyrfQ1rVKTk,3620
|
|
239
240
|
runtimepy/primitives/scaling.py,sha256=Vtxp2CSBahqPp4i2-IS4wjbcC023xwf-dqZMbYWf3V4,1144
|
|
240
241
|
runtimepy/primitives/string.py,sha256=ic5VKhXCSIwEOUfqIb1VUpZPwjdAcBul-cLLIihVkQI,2532
|
|
241
|
-
runtimepy/primitives/array/__init__.py,sha256=
|
|
242
|
+
runtimepy/primitives/array/__init__.py,sha256=ZVJt4810hTFYMdolY_R75lRRHHaNKxZ4comBvuK_69E,8956
|
|
242
243
|
runtimepy/primitives/field/__init__.py,sha256=iHZSQBozMpfiv_5KE_GIX1FAvDB9unUO0xmWZHiA_Jk,4491
|
|
243
244
|
runtimepy/primitives/field/fields.py,sha256=jDNi1tl2Xc3GBmt6QJuqxbhP8MtxgertGbPFmDXa7b4,7481
|
|
244
245
|
runtimepy/primitives/field/manager/__init__.py,sha256=BCRi6-_5OOJ8kz78JHkiLp8cZ71KA1uiF2zq5FFe9js,2586
|
|
245
246
|
runtimepy/primitives/field/manager/base.py,sha256=EyWs5D9_reKOTLkh8PuW45ySjCh31fY_qrtFIcmIOV4,6914
|
|
246
|
-
runtimepy/primitives/serializable/__init__.py,sha256=
|
|
247
|
-
runtimepy/primitives/serializable/base.py,sha256=
|
|
247
|
+
runtimepy/primitives/serializable/__init__.py,sha256=R9_derxnK1OCaYyqBZA4CCjPkXCBw6InkE8-3Zy75Uk,399
|
|
248
|
+
runtimepy/primitives/serializable/base.py,sha256=ij-9WaUZIMljS1iztciuz0XTWJdlKuyNjvf5nu0HxrE,5471
|
|
248
249
|
runtimepy/primitives/serializable/fixed.py,sha256=rhr6uVbo0Lvazk4fLI7iei-vVNEwP1J8-LoUjW1NaMI,1077
|
|
249
250
|
runtimepy/primitives/serializable/framer.py,sha256=rsoGQz6vD7v_EMu67aqxVqbvmbs6hjytXZ8dHLBM0SQ,1815
|
|
250
251
|
runtimepy/primitives/serializable/prefixed.py,sha256=oQXW0pGRovKolheL5ZL2m9aNVMCtKTAi5OlC9KW0iKI,2855
|
|
251
252
|
runtimepy/primitives/types/__init__.py,sha256=JUJpDFIjDUYo-Jnx5sZnkmbGLVjIHVsRcvBjVlJ7fsA,1588
|
|
252
253
|
runtimepy/primitives/types/base.py,sha256=rR1JkExMV2FJmvU-WfgnikG-UtFfsXGs_eBCIV6II1A,4879
|
|
253
254
|
runtimepy/primitives/types/bool.py,sha256=J0SYdp-9eIRs337d9qnw2f7IXTPQj_F21ugMIJ8-Hy4,547
|
|
254
|
-
runtimepy/primitives/types/bounds.py,sha256=
|
|
255
|
+
runtimepy/primitives/types/bounds.py,sha256=Hc2GWu4qJMEAF8IiDWFA_6VCNUtrNf5RmiEbSJ76dJI,1145
|
|
255
256
|
runtimepy/primitives/types/float.py,sha256=yjiU1AGzekY8PjDcLNdoXMGDsdP5aDYWjLb3_RntRpA,1388
|
|
256
257
|
runtimepy/primitives/types/int.py,sha256=Gjro7RgPL1girVVXhvDErvRwxlfHclMr7tZEFYj-Uj4,3807
|
|
257
258
|
runtimepy/registry/__init__.py,sha256=NpMxvdmjRtE3jCCOuYU_CPpYWqCZ5byXWhJNTB6jZUk,3425
|
|
@@ -284,9 +285,9 @@ runtimepy/tui/task.py,sha256=nUZo9fuOC-k1Wpqdzkv9v1tQirCI28fZVgcC13Ijvus,1093
|
|
|
284
285
|
runtimepy/tui/channels/__init__.py,sha256=evDaiIn-YS9uGhdo8ZGtP9VK1ek6sr_P1nJ9JuSET0o,4536
|
|
285
286
|
runtimepy/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
286
287
|
runtimepy/ui/controls.py,sha256=yvT7h3thbYaitsakcIAJ90EwKzJ4b-jnc6p3UuVf_XE,1241
|
|
287
|
-
runtimepy-5.
|
|
288
|
-
runtimepy-5.
|
|
289
|
-
runtimepy-5.
|
|
290
|
-
runtimepy-5.
|
|
291
|
-
runtimepy-5.
|
|
292
|
-
runtimepy-5.
|
|
288
|
+
runtimepy-5.11.0.dist-info/licenses/LICENSE,sha256=yKBRwbO-cOPBrlpsZmJkkSa33DfY31aE8t7lZ0DwlUo,1071
|
|
289
|
+
runtimepy-5.11.0.dist-info/METADATA,sha256=mj58S6d33EOyEgeZSpDwo9UU5imTeKZ2r5pRdrkguFk,9395
|
|
290
|
+
runtimepy-5.11.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
291
|
+
runtimepy-5.11.0.dist-info/entry_points.txt,sha256=-btVBkYv7ybcopqZ_pRky-bEzu3vhbaG3W3Z7ERBiFE,51
|
|
292
|
+
runtimepy-5.11.0.dist-info/top_level.txt,sha256=0jPmh6yqHyyJJDwEID-LpQly-9kQ3WRMjH7Lix8peLg,10
|
|
293
|
+
runtimepy-5.11.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|