runtimepy 5.14.2__py3-none-any.whl → 5.15.1__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/__init__.py +1 -4
- runtimepy/channel/environment/__init__.py +93 -2
- runtimepy/channel/environment/create.py +16 -1
- runtimepy/channel/environment/sample.py +10 -2
- runtimepy/channel/registry.py +2 -3
- runtimepy/codec/protocol/base.py +34 -14
- runtimepy/codec/protocol/json.py +5 -3
- runtimepy/codec/system/__init__.py +6 -2
- runtimepy/control/source.py +1 -1
- runtimepy/data/404.md +16 -0
- runtimepy/data/base.yaml +3 -0
- runtimepy/data/css/bootstrap_extra.css +59 -44
- runtimepy/data/css/main.css +23 -4
- runtimepy/data/dummy_load.yaml +5 -2
- runtimepy/data/factories.yaml +1 -0
- runtimepy/data/js/classes/App.js +54 -2
- runtimepy/data/js/classes/ChannelTable.js +6 -8
- runtimepy/data/js/classes/Plot.js +9 -4
- runtimepy/data/js/classes/TabFilter.js +47 -9
- runtimepy/data/js/classes/TabInterface.js +106 -11
- runtimepy/data/js/classes/WindowHashManager.js +30 -15
- runtimepy/data/js/init.js +18 -1
- runtimepy/data/js/markdown_page.js +10 -0
- runtimepy/data/js/sample.js +1 -0
- runtimepy/data/schemas/BitFields.yaml +9 -0
- runtimepy/data/schemas/RuntimeEnum.yaml +6 -0
- runtimepy/data/schemas/StructConfig.yaml +9 -1
- runtimepy/data/static/css/bootstrap-icons.min.css +4 -3
- runtimepy/data/static/css/bootstrap.min.css +3 -4
- runtimepy/data/static/css/fonts/bootstrap-icons.woff +0 -0
- runtimepy/data/static/css/fonts/bootstrap-icons.woff2 +0 -0
- runtimepy/data/static/js/bootstrap.bundle.min.js +5 -4
- runtimepy/data/static/js/webglplot.umd.min.js +2 -1
- runtimepy/data/static/svg/outline-dark.svg +22 -0
- runtimepy/data/static/svg/outline-light.svg +22 -0
- runtimepy/enum/__init__.py +13 -1
- runtimepy/enum/registry.py +13 -1
- runtimepy/message/__init__.py +3 -3
- runtimepy/mixins/logging.py +6 -1
- runtimepy/net/__init__.py +0 -2
- runtimepy/net/arbiter/info.py +36 -4
- runtimepy/net/arbiter/struct/__init__.py +3 -2
- runtimepy/net/connection.py +6 -7
- runtimepy/net/html/__init__.py +29 -11
- runtimepy/net/html/bootstrap/__init__.py +2 -2
- runtimepy/net/html/bootstrap/elements.py +44 -24
- runtimepy/net/html/bootstrap/tabs.py +18 -11
- runtimepy/net/http/__init__.py +3 -3
- runtimepy/net/http/request_target.py +3 -3
- runtimepy/net/mixin.py +4 -2
- runtimepy/net/server/__init__.py +16 -9
- runtimepy/net/server/app/__init__.py +1 -0
- runtimepy/net/server/app/create.py +3 -3
- runtimepy/net/server/app/env/__init__.py +30 -4
- runtimepy/net/server/app/env/settings.py +4 -7
- runtimepy/net/server/app/env/tab/base.py +2 -1
- runtimepy/net/server/app/env/tab/controls.py +141 -27
- runtimepy/net/server/app/env/tab/html.py +68 -26
- runtimepy/net/server/app/env/widgets.py +115 -61
- runtimepy/net/server/app/landing_page.py +1 -1
- runtimepy/net/server/app/tab.py +12 -3
- runtimepy/net/server/html.py +2 -2
- runtimepy/net/server/json.py +1 -1
- runtimepy/net/server/markdown.py +29 -12
- runtimepy/net/server/mux.py +29 -0
- runtimepy/net/stream/__init__.py +6 -5
- runtimepy/net/stream/base.py +4 -2
- runtimepy/net/tcp/connection.py +5 -3
- runtimepy/net/tcp/http/__init__.py +10 -9
- runtimepy/net/tcp/protocol.py +2 -2
- runtimepy/net/tcp/scpi/__init__.py +5 -2
- runtimepy/net/tcp/telnet/__init__.py +2 -1
- runtimepy/net/udp/connection.py +10 -6
- runtimepy/net/udp/protocol.py +5 -6
- runtimepy/net/udp/queue.py +5 -2
- runtimepy/net/udp/tftp/base.py +2 -1
- runtimepy/net/websocket/connection.py +58 -9
- runtimepy/primitives/array/__init__.py +7 -5
- runtimepy/primitives/base.py +3 -2
- runtimepy/primitives/field/__init__.py +35 -2
- runtimepy/primitives/field/fields.py +11 -2
- runtimepy/primitives/field/manager/base.py +19 -2
- runtimepy/primitives/serializable/base.py +5 -2
- runtimepy/primitives/serializable/fixed.py +5 -2
- runtimepy/primitives/serializable/prefixed.py +4 -1
- runtimepy/primitives/types/base.py +4 -1
- runtimepy/primitives/types/bounds.py +10 -4
- runtimepy/registry/__init__.py +20 -0
- runtimepy/registry/name.py +6 -0
- runtimepy/requirements.txt +2 -2
- runtimepy/ui/controls.py +20 -1
- {runtimepy-5.14.2.dist-info → runtimepy-5.15.1.dist-info}/METADATA +6 -6
- {runtimepy-5.14.2.dist-info → runtimepy-5.15.1.dist-info}/RECORD +98 -94
- {runtimepy-5.14.2.dist-info → runtimepy-5.15.1.dist-info}/WHEEL +1 -1
- runtimepy/data/404.html +0 -7
- {runtimepy-5.14.2.dist-info → runtimepy-5.15.1.dist-info}/entry_points.txt +0 -0
- {runtimepy-5.14.2.dist-info → runtimepy-5.15.1.dist-info}/licenses/LICENSE +0 -0
- {runtimepy-5.14.2.dist-info → runtimepy-5.15.1.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=7da25db9f79bc00e444a7898020e2a26
|
|
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.15.1"
|
|
14
14
|
|
|
15
15
|
# runtimepy-specific content.
|
|
16
16
|
METRICS_NAME = "metrics"
|
runtimepy/channel/__init__.py
CHANGED
|
@@ -29,10 +29,7 @@ from runtimepy.primitives.int import Uint32 as _Uint32
|
|
|
29
29
|
from runtimepy.primitives.int import Uint64 as _Uint64
|
|
30
30
|
from runtimepy.primitives.types import AnyPrimitiveType as _AnyPrimitiveType
|
|
31
31
|
from runtimepy.registry.item import RegistryItem as _RegistryItem
|
|
32
|
-
|
|
33
|
-
Literal = int | float | bool
|
|
34
|
-
Default = _Optional[Literal]
|
|
35
|
-
Controls = dict[str, Literal | dict[str, Literal]]
|
|
32
|
+
from runtimepy.ui.controls import Controls, Default
|
|
36
33
|
|
|
37
34
|
|
|
38
35
|
class Channel(_RegistryItem, _EnumMixin, _Generic[_T]):
|
|
@@ -3,10 +3,12 @@ A module implementing a channel environment.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
# built-in
|
|
6
|
+
from contextlib import ExitStack as _ExitStack
|
|
6
7
|
from typing import Iterator as _Iterator
|
|
8
|
+
from typing import Optional
|
|
9
|
+
from typing import cast as _cast
|
|
7
10
|
|
|
8
11
|
# internal
|
|
9
|
-
from runtimepy.channel import Default as _Default
|
|
10
12
|
from runtimepy.channel.environment.array import (
|
|
11
13
|
ArrayChannelEnvironment as _ArrayChannelEnvironment,
|
|
12
14
|
)
|
|
@@ -19,6 +21,23 @@ from runtimepy.channel.environment.file import (
|
|
|
19
21
|
from runtimepy.channel.environment.telemetry import (
|
|
20
22
|
TelemetryChannelEnvironment as _TelemetryChannelEnvironment,
|
|
21
23
|
)
|
|
24
|
+
from runtimepy.codec.protocol import Protocol as _Protocol
|
|
25
|
+
from runtimepy.codec.protocol.base import FieldSpec as _FieldSpec
|
|
26
|
+
from runtimepy.primitives import AnyPrimitive
|
|
27
|
+
from runtimepy.ui.controls import Controls, Default, bit_slider
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def regular_channel_controls(
|
|
31
|
+
primitive: AnyPrimitive, commandable: bool
|
|
32
|
+
) -> Optional[Controls]:
|
|
33
|
+
"""Get channel controls for a regular primitive."""
|
|
34
|
+
|
|
35
|
+
controls = None
|
|
36
|
+
|
|
37
|
+
if commandable and primitive.kind.is_integer and primitive.kind.bits <= 32:
|
|
38
|
+
controls = bit_slider(primitive.kind.bits, primitive.kind.signed)
|
|
39
|
+
|
|
40
|
+
return controls
|
|
22
41
|
|
|
23
42
|
|
|
24
43
|
class ChannelEnvironment(
|
|
@@ -29,13 +48,85 @@ class ChannelEnvironment(
|
|
|
29
48
|
):
|
|
30
49
|
"""A class integrating channel and enumeration registries."""
|
|
31
50
|
|
|
51
|
+
def register_protocol(
|
|
52
|
+
self, protocol: _Protocol, commandable: bool
|
|
53
|
+
) -> None:
|
|
54
|
+
"""Register protocol elements as named channels and fields."""
|
|
55
|
+
|
|
56
|
+
# Register any new enumerations.
|
|
57
|
+
self.enums.register_from_other(protocol.enum_registry)
|
|
58
|
+
|
|
59
|
+
# need to handle defaults
|
|
60
|
+
|
|
61
|
+
for item in protocol.build:
|
|
62
|
+
# Handle regular primitive fields.
|
|
63
|
+
if isinstance(item, _FieldSpec):
|
|
64
|
+
if item.is_array():
|
|
65
|
+
assert item.array_length is not None
|
|
66
|
+
with self.names_pushed(item.name):
|
|
67
|
+
for idx in range(item.array_length):
|
|
68
|
+
primitive = protocol.get_primitive(
|
|
69
|
+
item.name, index=idx
|
|
70
|
+
)
|
|
71
|
+
self.channel(
|
|
72
|
+
str(idx),
|
|
73
|
+
kind=primitive,
|
|
74
|
+
commandable=commandable,
|
|
75
|
+
enum=item.enum,
|
|
76
|
+
controls=regular_channel_controls(
|
|
77
|
+
primitive, commandable
|
|
78
|
+
),
|
|
79
|
+
)
|
|
80
|
+
else:
|
|
81
|
+
primitive = protocol.get_primitive(item.name)
|
|
82
|
+
self.channel(
|
|
83
|
+
item.name,
|
|
84
|
+
kind=primitive,
|
|
85
|
+
commandable=commandable,
|
|
86
|
+
enum=item.enum,
|
|
87
|
+
controls=regular_channel_controls(
|
|
88
|
+
primitive, commandable
|
|
89
|
+
),
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# Handle nested protocols.
|
|
93
|
+
elif isinstance(item[0], str):
|
|
94
|
+
name = item[0]
|
|
95
|
+
candidates = protocol.serializables[name]
|
|
96
|
+
if isinstance(candidates[0], _Protocol):
|
|
97
|
+
with self.names_pushed(name):
|
|
98
|
+
for idx, candidate in enumerate(candidates):
|
|
99
|
+
with _ExitStack() as stack:
|
|
100
|
+
# Enter array-index namespace if applicable.
|
|
101
|
+
if len(candidates) > 1:
|
|
102
|
+
stack.enter_context(
|
|
103
|
+
self.names_pushed(str(idx))
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
self.register_protocol(
|
|
107
|
+
_cast(_Protocol, candidate), commandable
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
# Handle bit fields.
|
|
111
|
+
elif isinstance(item[0], int):
|
|
112
|
+
fields = protocol.get_fields(item[0])
|
|
113
|
+
for field in fields.fields.values():
|
|
114
|
+
field.commandable = commandable
|
|
115
|
+
# add sliders for non enum non bool (check enum fields too)
|
|
116
|
+
self.add_fields(
|
|
117
|
+
item[1],
|
|
118
|
+
fields,
|
|
119
|
+
commandable=commandable,
|
|
120
|
+
controls=bit_slider(fields.raw.kind.bits, False),
|
|
121
|
+
)
|
|
122
|
+
|
|
32
123
|
def search_names(
|
|
33
124
|
self, pattern: str, exact: bool = False
|
|
34
125
|
) -> _Iterator[str]:
|
|
35
126
|
"""Search for names belonging to this environment."""
|
|
36
127
|
yield from self.channels.names.search(pattern, exact=exact)
|
|
37
128
|
|
|
38
|
-
def set_default(self, key: str, default:
|
|
129
|
+
def set_default(self, key: str, default: Default) -> None:
|
|
39
130
|
"""Set a new default value for a channel."""
|
|
40
131
|
|
|
41
132
|
chan, _ = self[key]
|
|
@@ -28,6 +28,7 @@ from runtimepy.enum.types import EnumTypelike as _EnumTypelike
|
|
|
28
28
|
from runtimepy.mapping import EnumMappingData as _EnumMappingData
|
|
29
29
|
from runtimepy.primitives import ChannelScaling, Primitive
|
|
30
30
|
from runtimepy.primitives import Primitivelike as _Primitivelike
|
|
31
|
+
from runtimepy.primitives.field.fields import BitFields as _BitFields
|
|
31
32
|
from runtimepy.registry.name import RegistryKey as _RegistryKey
|
|
32
33
|
|
|
33
34
|
|
|
@@ -74,10 +75,22 @@ class CreateChannelEnvironment(_BaseChannelEnvironment):
|
|
|
74
75
|
|
|
75
76
|
# Keep track of any new enum channels.
|
|
76
77
|
if enum is not None:
|
|
77
|
-
|
|
78
|
+
runtime = self.enums[enum]
|
|
79
|
+
self.channel_enums[result] = runtime
|
|
80
|
+
if runtime.default:
|
|
81
|
+
self[name] = runtime.default
|
|
78
82
|
|
|
79
83
|
return self[name]
|
|
80
84
|
|
|
85
|
+
def add_fields(
|
|
86
|
+
self, name: str, fields: _BitFields, **channel_kwargs
|
|
87
|
+
) -> None:
|
|
88
|
+
"""Add bit fields to this channel environment."""
|
|
89
|
+
|
|
90
|
+
self.channel(name, kind=fields.raw, **channel_kwargs)
|
|
91
|
+
with self.names_pushed(name):
|
|
92
|
+
self.fields.add(fields, namespace=self._namespace, track=True)
|
|
93
|
+
|
|
81
94
|
def int_channel(
|
|
82
95
|
self,
|
|
83
96
|
name: str,
|
|
@@ -171,6 +184,7 @@ class CreateChannelEnvironment(_BaseChannelEnvironment):
|
|
|
171
184
|
items: _EnumMappingData = None,
|
|
172
185
|
namespace: _Namespace = None,
|
|
173
186
|
primitive: str = DEFAULT_ENUM_PRIMITIVE,
|
|
187
|
+
**kwargs,
|
|
174
188
|
) -> _RuntimeEnum:
|
|
175
189
|
"""Create a new enum from the environment."""
|
|
176
190
|
|
|
@@ -179,6 +193,7 @@ class CreateChannelEnvironment(_BaseChannelEnvironment):
|
|
|
179
193
|
kind=kind,
|
|
180
194
|
items=items,
|
|
181
195
|
primitive=primitive,
|
|
196
|
+
**kwargs,
|
|
182
197
|
)
|
|
183
198
|
assert result is not None, f"Can't create enum '{name}'!"
|
|
184
199
|
return result
|
|
@@ -33,6 +33,7 @@ def sample_int_enum(
|
|
|
33
33
|
"nine": 9,
|
|
34
34
|
"ten": 10,
|
|
35
35
|
},
|
|
36
|
+
default="three",
|
|
36
37
|
)
|
|
37
38
|
|
|
38
39
|
|
|
@@ -99,6 +100,7 @@ def sample_fields(env: ChannelEnvironment, enum: str = "SampleEnum") -> None:
|
|
|
99
100
|
1,
|
|
100
101
|
commandable=True,
|
|
101
102
|
description="Sample bit flag.",
|
|
103
|
+
default=True,
|
|
102
104
|
)
|
|
103
105
|
)
|
|
104
106
|
env.add_field(
|
|
@@ -109,13 +111,19 @@ def sample_fields(env: ChannelEnvironment, enum: str = "SampleEnum") -> None:
|
|
|
109
111
|
2,
|
|
110
112
|
enum=enum if enum else None,
|
|
111
113
|
commandable=True,
|
|
114
|
+
default="three" if enum else 3,
|
|
112
115
|
description="Sample bit field.",
|
|
113
116
|
)
|
|
114
117
|
)
|
|
115
118
|
env.add_field(
|
|
116
119
|
BitField(
|
|
117
|
-
env.namespace(name="field2"),
|
|
118
|
-
|
|
120
|
+
env.namespace(name="field2"),
|
|
121
|
+
prim,
|
|
122
|
+
4,
|
|
123
|
+
4,
|
|
124
|
+
default=0,
|
|
125
|
+
commandable=True,
|
|
126
|
+
).set_slider()
|
|
119
127
|
)
|
|
120
128
|
|
|
121
129
|
|
runtimepy/channel/registry.py
CHANGED
|
@@ -16,7 +16,6 @@ from vcorelib.io.types import JsonObject as _JsonObject
|
|
|
16
16
|
# internal
|
|
17
17
|
from runtimepy.channel import AnyChannel as _AnyChannel
|
|
18
18
|
from runtimepy.channel import Channel as _Channel
|
|
19
|
-
from runtimepy.channel import Default as _Default
|
|
20
19
|
from runtimepy.channel.event.header import PrimitiveEventHeader
|
|
21
20
|
from runtimepy.codec.protocol import Protocol
|
|
22
21
|
from runtimepy.mapping import DEFAULT_PATTERN
|
|
@@ -29,7 +28,7 @@ from runtimepy.primitives.types.base import PythonPrimitive
|
|
|
29
28
|
from runtimepy.registry import Registry as _Registry
|
|
30
29
|
from runtimepy.registry.name import NameRegistry as _NameRegistry
|
|
31
30
|
from runtimepy.registry.name import RegistryKey as _RegistryKey
|
|
32
|
-
from runtimepy.ui.controls import Controlslike, normalize_controls
|
|
31
|
+
from runtimepy.ui.controls import Controlslike, Default, normalize_controls
|
|
33
32
|
|
|
34
33
|
|
|
35
34
|
class ChannelNameRegistry(_NameRegistry):
|
|
@@ -92,7 +91,7 @@ class ChannelRegistry(_Registry[_Channel[_Any]]):
|
|
|
92
91
|
enum: _RegistryKey = None,
|
|
93
92
|
scaling: ChannelScaling = None,
|
|
94
93
|
description: str = None,
|
|
95
|
-
default:
|
|
94
|
+
default: Default = None,
|
|
96
95
|
controls: Controlslike = None,
|
|
97
96
|
**kwargs,
|
|
98
97
|
) -> _Optional[_AnyChannel]:
|
runtimepy/codec/protocol/base.py
CHANGED
|
@@ -47,6 +47,10 @@ class FieldSpec(NamedTuple):
|
|
|
47
47
|
enum: _Optional[_RegistryKey] = None
|
|
48
48
|
array_length: _Optional[int] = None
|
|
49
49
|
|
|
50
|
+
def is_array(self) -> bool:
|
|
51
|
+
"""Determine if this instance is an array."""
|
|
52
|
+
return self.array_length is not None and self.array_length > 1
|
|
53
|
+
|
|
50
54
|
def asdict(self) -> _JsonObject:
|
|
51
55
|
"""Obtain a dictionary representing this instance."""
|
|
52
56
|
|
|
@@ -91,14 +95,14 @@ class ProtocolBase(PrimitiveArray):
|
|
|
91
95
|
self.alias = alias
|
|
92
96
|
|
|
93
97
|
# Register the byte-order enumeration if it's not present.
|
|
94
|
-
self.
|
|
95
|
-
if not self.
|
|
96
|
-
_ByteOrder.register_enum(self.
|
|
98
|
+
self.enum_registry = enum_registry
|
|
99
|
+
if not self.enum_registry.get("ByteOrder"):
|
|
100
|
+
_ByteOrder.register_enum(self.enum_registry)
|
|
97
101
|
|
|
98
102
|
# Each instance gets its own array.
|
|
99
103
|
if not isinstance(byte_order, _ByteOrder):
|
|
100
104
|
byte_order = _ByteOrder(
|
|
101
|
-
self.
|
|
105
|
+
self.enum_registry["ByteOrder"].get_int(byte_order)
|
|
102
106
|
)
|
|
103
107
|
|
|
104
108
|
super().__init__(byte_order=byte_order)
|
|
@@ -108,14 +112,14 @@ class ProtocolBase(PrimitiveArray):
|
|
|
108
112
|
self.names = names
|
|
109
113
|
|
|
110
114
|
if fields is None:
|
|
111
|
-
fields = BitFieldsManager(self.names, self.
|
|
115
|
+
fields = BitFieldsManager(self.names, self.enum_registry)
|
|
112
116
|
self._fields = fields
|
|
113
117
|
|
|
114
118
|
self._regular_fields: dict[str, list[_AnyPrimitive]] = {}
|
|
115
119
|
self._enum_fields: dict[str, _RuntimeEnum] = {}
|
|
116
120
|
|
|
117
121
|
# Keep track of the order that the protocol was created.
|
|
118
|
-
self.
|
|
122
|
+
self.build: ProtocolBuild = []
|
|
119
123
|
|
|
120
124
|
# Keep track of named serializables.
|
|
121
125
|
self.serializables: SerializableMap = {}
|
|
@@ -154,10 +158,10 @@ class ProtocolBase(PrimitiveArray):
|
|
|
154
158
|
"""Create another protocol instance from this one."""
|
|
155
159
|
|
|
156
160
|
return self.__class__(
|
|
157
|
-
self.
|
|
161
|
+
self.enum_registry,
|
|
158
162
|
names=self.names,
|
|
159
163
|
fields=_copy(self._fields),
|
|
160
|
-
build=self.
|
|
164
|
+
build=self.build,
|
|
161
165
|
byte_order=self.byte_order,
|
|
162
166
|
identifier=self.id,
|
|
163
167
|
identifier_primitive=self.id_primitive.kind.name,
|
|
@@ -183,7 +187,7 @@ class ProtocolBase(PrimitiveArray):
|
|
|
183
187
|
self.register_name(name)
|
|
184
188
|
|
|
185
189
|
instances = self.add_to_end(serializable, array_length=array_length)
|
|
186
|
-
self.
|
|
190
|
+
self.build.append((name, len(instances)))
|
|
187
191
|
|
|
188
192
|
assert name not in self.serializables, name
|
|
189
193
|
self.serializables[name] = instances
|
|
@@ -209,8 +213,9 @@ class ProtocolBase(PrimitiveArray):
|
|
|
209
213
|
|
|
210
214
|
self.register_name(name)
|
|
211
215
|
|
|
216
|
+
runtime_enum = None
|
|
212
217
|
if enum is not None:
|
|
213
|
-
runtime_enum = self.
|
|
218
|
+
runtime_enum = self.enum_registry[enum]
|
|
214
219
|
self._enum_fields[name] = runtime_enum
|
|
215
220
|
|
|
216
221
|
# Allow the primitive type to be overridden when passed as a
|
|
@@ -221,13 +226,20 @@ class ProtocolBase(PrimitiveArray):
|
|
|
221
226
|
assert kind is not None
|
|
222
227
|
inst = _normalize_instance(kind)
|
|
223
228
|
|
|
229
|
+
# Set enum defaults.
|
|
230
|
+
if runtime_enum is not None and runtime_enum.default:
|
|
231
|
+
inst.value = runtime_enum.get_int(runtime_enum.default)
|
|
232
|
+
|
|
224
233
|
assert name not in self._regular_fields, name
|
|
225
234
|
self._regular_fields[name] = self.add(inst, array_length=array_length)
|
|
226
235
|
|
|
227
236
|
if track:
|
|
228
|
-
self.
|
|
237
|
+
self.build.append(
|
|
229
238
|
FieldSpec(
|
|
230
|
-
name,
|
|
239
|
+
name,
|
|
240
|
+
inst.kind.name,
|
|
241
|
+
enum,
|
|
242
|
+
array_length=array_length,
|
|
231
243
|
)
|
|
232
244
|
)
|
|
233
245
|
|
|
@@ -240,7 +252,7 @@ class ProtocolBase(PrimitiveArray):
|
|
|
240
252
|
if index is None:
|
|
241
253
|
index = self._fields.add(fields)
|
|
242
254
|
|
|
243
|
-
self.
|
|
255
|
+
self.build.append((index, name))
|
|
244
256
|
self.add_field(name, kind=fields.raw, track=False)
|
|
245
257
|
|
|
246
258
|
@contextmanager
|
|
@@ -253,6 +265,14 @@ class ProtocolBase(PrimitiveArray):
|
|
|
253
265
|
yield new
|
|
254
266
|
self._add_bit_fields(name, new)
|
|
255
267
|
|
|
268
|
+
def get_primitive(self, name: str, index: int = 0) -> _AnyPrimitive:
|
|
269
|
+
"""Get an underlying primitive instance."""
|
|
270
|
+
return self._regular_fields[name][index]
|
|
271
|
+
|
|
272
|
+
def get_fields(self, index: int) -> _BitFields:
|
|
273
|
+
"""Get a bit-fields instance from its build identifier."""
|
|
274
|
+
return self._fields.fields[index]
|
|
275
|
+
|
|
256
276
|
def value(
|
|
257
277
|
self, name: str, resolve_enum: bool = True, index: int = 0
|
|
258
278
|
) -> ProtocolPrimitive:
|
|
@@ -261,7 +281,7 @@ class ProtocolBase(PrimitiveArray):
|
|
|
261
281
|
val: ProtocolPrimitive = 0
|
|
262
282
|
|
|
263
283
|
if name in self._regular_fields:
|
|
264
|
-
val = self.
|
|
284
|
+
val = self.get_primitive(name, index=index).value
|
|
265
285
|
|
|
266
286
|
# Resolve the enum value.
|
|
267
287
|
if resolve_enum and name in self._enum_fields:
|
runtimepy/codec/protocol/json.py
CHANGED
|
@@ -74,7 +74,7 @@ class JsonProtocol(ProtocolBase):
|
|
|
74
74
|
json_obj.update(
|
|
75
75
|
{
|
|
76
76
|
name: _cast(_JsonValue, val.asdict())
|
|
77
|
-
for name, val in self.
|
|
77
|
+
for name, val in self.enum_registry.items.items()
|
|
78
78
|
if val.id in enum_ids and name not in json_obj
|
|
79
79
|
}
|
|
80
80
|
)
|
|
@@ -83,7 +83,7 @@ class JsonProtocol(ProtocolBase):
|
|
|
83
83
|
build: list[
|
|
84
84
|
_Union[tuple[int, str], _JsonObject, str, tuple[str, int]]
|
|
85
85
|
] = []
|
|
86
|
-
for item in self.
|
|
86
|
+
for item in self.build:
|
|
87
87
|
if isinstance(item, FieldSpec):
|
|
88
88
|
build.append(item.asdict())
|
|
89
89
|
else:
|
|
@@ -120,7 +120,9 @@ class JsonProtocol(ProtocolBase):
|
|
|
120
120
|
if isinstance(item, dict):
|
|
121
121
|
build.append(
|
|
122
122
|
FieldSpec(
|
|
123
|
-
item["name"],
|
|
123
|
+
item["name"],
|
|
124
|
+
item["kind"],
|
|
125
|
+
enum=item.get("enum"),
|
|
124
126
|
)
|
|
125
127
|
)
|
|
126
128
|
else:
|
|
@@ -14,6 +14,7 @@ from vcorelib.namespace import CPP_DELIM, Namespace
|
|
|
14
14
|
from runtimepy.codec.protocol import Protocol
|
|
15
15
|
from runtimepy.enum import RuntimeEnum
|
|
16
16
|
from runtimepy.enum.registry import DEFAULT_ENUM_PRIMITIVE, RuntimeIntEnum
|
|
17
|
+
from runtimepy.mixins.logging import LogLevel
|
|
17
18
|
from runtimepy.primitives.byte_order import (
|
|
18
19
|
DEFAULT_BYTE_ORDER,
|
|
19
20
|
ByteOrder,
|
|
@@ -65,7 +66,7 @@ class TypeSystem(LoggerMixin):
|
|
|
65
66
|
self.root_namespace = global_namespace
|
|
66
67
|
|
|
67
68
|
# Register enums.
|
|
68
|
-
for enum in [ByteOrder]:
|
|
69
|
+
for enum in [ByteOrder, LogLevel]:
|
|
69
70
|
self.runtime_int_enum(enum)
|
|
70
71
|
|
|
71
72
|
self.root_namespace = global_namespace.child(*namespace)
|
|
@@ -103,12 +104,15 @@ class TypeSystem(LoggerMixin):
|
|
|
103
104
|
items: dict[str, int],
|
|
104
105
|
*namespace: str,
|
|
105
106
|
primitive: str = DEFAULT_ENUM_PRIMITIVE,
|
|
107
|
+
default: Union[str, bool, int] = None,
|
|
106
108
|
) -> None:
|
|
107
109
|
"""Register an enumeration."""
|
|
108
110
|
|
|
109
111
|
name = self._name(name, *namespace, check_available=True)
|
|
110
112
|
|
|
111
|
-
enum = self._enums.enum(
|
|
113
|
+
enum = self._enums.enum(
|
|
114
|
+
name, "int", items=items, primitive=primitive, default=default
|
|
115
|
+
)
|
|
112
116
|
assert enum is not None
|
|
113
117
|
self._register_primitive(name, enum.primitive)
|
|
114
118
|
|
runtimepy/control/source.py
CHANGED
runtimepy/data/404.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Resource Not Found (404)
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
<span id="target-label">target: <a id="target"></a></span>
|
|
6
|
+
<script>
|
|
7
|
+
const target = new URLSearchParams(window.location.search).get("target");
|
|
8
|
+
if (target) {
|
|
9
|
+
document.getElementById("target").href = target;
|
|
10
|
+
document.getElementById("target").innerHTML = target;
|
|
11
|
+
} else {
|
|
12
|
+
document.getElementById("target-label").style.display = "none";
|
|
13
|
+
}
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
home: [/](/)
|
runtimepy/data/base.yaml
CHANGED
|
@@ -1,23 +1,3 @@
|
|
|
1
|
-
.flex-column-scroll-bodge {
|
|
2
|
-
height: 100%;
|
|
3
|
-
flex-wrap: nowrap;
|
|
4
|
-
overflow-y: scroll;
|
|
5
|
-
flex-shrink: 0;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
.scroll {
|
|
9
|
-
overflow: scroll;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
.tab-content-bodge {
|
|
13
|
-
width: 100%;
|
|
14
|
-
height: 100%;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.button-bodge {
|
|
18
|
-
text-align: left;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
1
|
.collapsing {
|
|
22
2
|
transition: none !important;
|
|
23
3
|
}
|
|
@@ -35,24 +15,9 @@
|
|
|
35
15
|
max-width: 80%;
|
|
36
16
|
}
|
|
37
17
|
|
|
38
|
-
.table {
|
|
39
|
-
margin-bottom: 0;
|
|
40
|
-
width: auto;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.table-container {
|
|
44
|
-
overflow-x: scroll;
|
|
45
|
-
min-height: fit-content;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
18
|
.channel-column {
|
|
49
|
-
overflow-y: scroll;
|
|
50
|
-
overflow-x: hidden;
|
|
51
|
-
flex-grow: 0;
|
|
52
|
-
flex-shrink: 0;
|
|
53
|
-
|
|
54
19
|
/* Don't allow plot area to become too hidden. */
|
|
55
|
-
max-width:
|
|
20
|
+
max-width: min-content;
|
|
56
21
|
}
|
|
57
22
|
|
|
58
23
|
.channel-value {
|
|
@@ -75,36 +40,86 @@ select.form-select:hover {
|
|
|
75
40
|
}
|
|
76
41
|
|
|
77
42
|
textarea.text-logs {
|
|
78
|
-
min-height:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
border-top: 0;
|
|
43
|
+
min-height: 6em !important;
|
|
44
|
+
font-size: 14px;
|
|
45
|
+
background-image: linear-gradient(var(--bs-secondary-bg), var(--bs-tertiary-bg), var(--bs-secondary-bg));
|
|
83
46
|
}
|
|
84
47
|
|
|
85
48
|
.vertical-divider {
|
|
86
|
-
flex-basis:
|
|
87
|
-
|
|
88
|
-
|
|
49
|
+
flex-basis: 1.0em;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.text-code {
|
|
53
|
+
color: var(--bs-code-color) !important;
|
|
89
54
|
}
|
|
90
55
|
|
|
91
56
|
pre {
|
|
92
57
|
color: var(--bs-code-color);
|
|
93
58
|
}
|
|
94
59
|
|
|
60
|
+
input:hover {
|
|
61
|
+
background-color: var(--bs-tertiary-bg);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
input[type=range] {
|
|
65
|
+
touch-action: none;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
input[type=checkbox]:hover {
|
|
69
|
+
cursor: pointer;
|
|
70
|
+
}
|
|
71
|
+
|
|
95
72
|
.vertical-divider:hover {
|
|
96
73
|
cursor: col-resize;
|
|
97
74
|
background-color: var(--bs-highlight-bg) !important;
|
|
98
75
|
}
|
|
99
76
|
|
|
77
|
+
td, th {
|
|
78
|
+
background: 0 !important;
|
|
79
|
+
}
|
|
80
|
+
|
|
100
81
|
button:hover {
|
|
101
82
|
background-color: var(--bs-tertiary-bg);
|
|
102
83
|
}
|
|
103
84
|
|
|
85
|
+
select:hover {
|
|
86
|
+
background-color: var(--bs-tertiary-bg);
|
|
87
|
+
}
|
|
88
|
+
|
|
104
89
|
.channel-value-input {
|
|
105
90
|
width: 6em;
|
|
106
91
|
}
|
|
107
92
|
|
|
93
|
+
.bg-gradient-secondary-to-bottom {
|
|
94
|
+
background-image: linear-gradient(to bottom right, rgba(var(--bs-secondary-bg-rgb), 0), var(--bs-secondary-bg));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.bg-gradient-tertiary-to-bottom {
|
|
98
|
+
background-image: linear-gradient(to bottom, rgba(var(--bs-tertiary-bg-rgb), 0), var(--bs-tertiary-bg));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.bg-gradient-secondary-to-top {
|
|
102
|
+
background-image: linear-gradient(to top right, rgba(var(--bs-secondary-bg-rgb), 0), var(--bs-secondary-bg));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.bg-gradient-tertiary-to-top {
|
|
106
|
+
background-image: linear-gradient(to top, rgba(var(--bs-tertiary-bg-rgb), 0), var(--bs-tertiary-bg));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.bg-gradient-tertiary-top-bottom {
|
|
110
|
+
background-image: linear-gradient(to bottom, var(--bs-tertiary-bg), rgba(var(--bs-tertiary-bg-rgb), 0), var(--bs-tertiary-bg));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.border-start-info-subtle {
|
|
114
|
+
border-left: var(--bs-border-width) var(--bs-border-style) var(--bs-info-border-subtle);
|
|
115
|
+
}
|
|
116
|
+
.border-end-info-subtle {
|
|
117
|
+
border-right: var(--bs-border-width) var(--bs-border-style) var(--bs-info-border-subtle);
|
|
118
|
+
}
|
|
119
|
+
button.border-end-info-subtle:hover {
|
|
120
|
+
border-right: var(--bs-border-width) var(--bs-border-style) var(--bs-info-border-subtle);
|
|
121
|
+
}
|
|
122
|
+
|
|
108
123
|
/* Prefer 'CascadiaCode' and 'CascadiaMono' at the highest priority. */
|
|
109
124
|
:root, [data-bs-theme=dark], [data-bs-theme=light] {
|
|
110
125
|
--bs-font-sans-serif: CascadiaCode, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|