pystructtype 0.3.0__tar.gz → 0.4.0__tar.gz
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.
- {pystructtype-0.3.0 → pystructtype-0.4.0}/.github/workflows/build.yml +4 -4
- {pystructtype-0.3.0 → pystructtype-0.4.0}/.github/workflows/release.yml +1 -1
- {pystructtype-0.3.0 → pystructtype-0.4.0}/.gitignore +4 -0
- {pystructtype-0.3.0 → pystructtype-0.4.0}/PKG-INFO +8 -14
- {pystructtype-0.3.0 → pystructtype-0.4.0}/README.md +5 -11
- {pystructtype-0.3.0 → pystructtype-0.4.0}/docs/conf.py +3 -1
- {pystructtype-0.3.0 → pystructtype-0.4.0}/pyproject.toml +39 -24
- {pystructtype-0.3.0 → pystructtype-0.4.0}/src/pystructtype/__init__.py +2 -4
- pystructtype-0.4.0/src/pystructtype/bitstype.py +86 -0
- {pystructtype-0.3.0 → pystructtype-0.4.0}/src/pystructtype/structdataclass.py +84 -140
- {pystructtype-0.3.0 → pystructtype-0.4.0}/src/pystructtype/structtypes.py +50 -15
- {pystructtype-0.3.0 → pystructtype-0.4.0}/src/pystructtype/utils.py +8 -4
- {pystructtype-0.3.0 → pystructtype-0.4.0}/test/examples.py +14 -13
- pystructtype-0.4.0/test/test_bitstype.py +92 -0
- pystructtype-0.4.0/test/test_examples.py +9 -0
- pystructtype-0.4.0/test/test_structdataclass_additional.py +425 -0
- pystructtype-0.4.0/test/test_structtypes.py +150 -0
- pystructtype-0.4.0/test/test_utils.py +31 -0
- {pystructtype-0.3.0 → pystructtype-0.4.0}/tox.ini +2 -2
- pystructtype-0.4.0/uv.lock +797 -0
- pystructtype-0.3.0/.python-version +0 -1
- pystructtype-0.3.0/setup.cfg +0 -6
- pystructtype-0.3.0/src/pystructtype/bitstype.py +0 -142
- pystructtype-0.3.0/test/test_ctypes.py +0 -76
- pystructtype-0.3.0/uv.lock +0 -629
- {pystructtype-0.3.0 → pystructtype-0.4.0}/.readthedocs.yaml +0 -0
- {pystructtype-0.3.0 → pystructtype-0.4.0}/LICENSE.txt +0 -0
- {pystructtype-0.3.0 → pystructtype-0.4.0}/docs/autoapi_templates/python/module.rst_t +0 -0
- {pystructtype-0.3.0 → pystructtype-0.4.0}/docs/autoapi_templates/python/package.rst_t +0 -0
- {pystructtype-0.3.0 → pystructtype-0.4.0}/docs/index.rst +0 -0
- {pystructtype-0.3.0 → pystructtype-0.4.0}/src/pystructtype/py.typed +0 -0
- {pystructtype-0.3.0 → pystructtype-0.4.0}/test/__init__.py +0 -0
- {pystructtype-0.3.0 → pystructtype-0.4.0}/test/py.typed +0 -0
|
@@ -14,13 +14,13 @@ jobs:
|
|
|
14
14
|
- name: Set up Python
|
|
15
15
|
uses: actions/setup-python@v5
|
|
16
16
|
with:
|
|
17
|
-
python-version: 3.
|
|
17
|
+
python-version: 3.14
|
|
18
18
|
|
|
19
19
|
- name: Run Tests
|
|
20
20
|
run: |
|
|
21
21
|
uv sync
|
|
22
22
|
uv tool install tox
|
|
23
|
-
tox -e
|
|
23
|
+
tox -e py314
|
|
24
24
|
check:
|
|
25
25
|
runs-on: ubuntu-latest
|
|
26
26
|
steps:
|
|
@@ -33,7 +33,7 @@ jobs:
|
|
|
33
33
|
- name: Set up Python
|
|
34
34
|
uses: actions/setup-python@v5
|
|
35
35
|
with:
|
|
36
|
-
python-version: 3.
|
|
36
|
+
python-version: 3.14
|
|
37
37
|
|
|
38
38
|
- name: Check Formatting
|
|
39
39
|
run: |
|
|
@@ -53,7 +53,7 @@ jobs:
|
|
|
53
53
|
- name: Set up Python
|
|
54
54
|
uses: actions/setup-python@v5
|
|
55
55
|
with:
|
|
56
|
-
python-version: 3.
|
|
56
|
+
python-version: 3.14
|
|
57
57
|
|
|
58
58
|
- name: Check Formatting
|
|
59
59
|
run: |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pystructtype
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Leverage Python Types to Define C-Struct Interfaces
|
|
5
5
|
Project-URL: Homepage, https://github.com/fchorney/pystructtype
|
|
6
6
|
Project-URL: Documentation, https://pystructtype.readthedocs.io/en/latest/
|
|
@@ -15,9 +15,9 @@ Classifier: Intended Audience :: Developers
|
|
|
15
15
|
Classifier: License :: OSI Approved :: MIT License
|
|
16
16
|
Classifier: Natural Language :: English
|
|
17
17
|
Classifier: Operating System :: OS Independent
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
19
|
Classifier: Topic :: Utilities
|
|
20
|
-
Requires-Python:
|
|
20
|
+
Requires-Python: <4.0,>=3.14
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
|
|
23
23
|
# PyStructTypes
|
|
@@ -56,7 +56,6 @@ struct MyStruct {
|
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
```python
|
|
59
|
-
@struct_dataclass
|
|
60
59
|
class MyStruct(StructDataclass):
|
|
61
60
|
myNum: int16_t
|
|
62
61
|
myLetter: char_t
|
|
@@ -83,7 +82,6 @@ struct MyStruct {
|
|
|
83
82
|
};
|
|
84
83
|
```
|
|
85
84
|
```python
|
|
86
|
-
@struct_dataclass
|
|
87
85
|
class MyStruct(StructDataclass):
|
|
88
86
|
myInts: Annotated[list[uint8_t], TypeMeta(size=4)]
|
|
89
87
|
myBiggerInts: Annotated[list[uint16_t], TypeMeta(size=2)]
|
|
@@ -109,7 +107,6 @@ struct MyStruct {
|
|
|
109
107
|
```
|
|
110
108
|
|
|
111
109
|
```python
|
|
112
|
-
@struct_dataclass
|
|
113
110
|
class MyStruct(StructDataclass):
|
|
114
111
|
myInt: uint8_t = 5
|
|
115
112
|
myInts: Annnotated[list[uint8_t], TypeMeta(size=2, default=1)]
|
|
@@ -139,7 +136,6 @@ struct MyStruct {
|
|
|
139
136
|
};
|
|
140
137
|
```
|
|
141
138
|
```python
|
|
142
|
-
@struct_dataclass
|
|
143
139
|
class MyStruct(StructDataclass):
|
|
144
140
|
myStr: Annotated[string_t, TypeMeta[str](chunk_size=3)]
|
|
145
141
|
myStrList: Annotated[list[string_t], TypeMeta[str](size=2, chunk_size=3)]
|
|
@@ -169,8 +165,9 @@ enum ConfigFlags {
|
|
|
169
165
|
```
|
|
170
166
|
|
|
171
167
|
```python
|
|
172
|
-
|
|
173
|
-
|
|
168
|
+
class FlagsType(BitsType):
|
|
169
|
+
__bits_type__ = uint8_t
|
|
170
|
+
__bits_definition__ = {"lights_flag": 0, "platform_flag": 1}
|
|
174
171
|
|
|
175
172
|
f = FlagsType()
|
|
176
173
|
f.decode([3])
|
|
@@ -200,7 +197,6 @@ struct MyStruct {
|
|
|
200
197
|
```
|
|
201
198
|
|
|
202
199
|
```python
|
|
203
|
-
@struct_dataclass
|
|
204
200
|
class EnabledSensors(StructDataclass):
|
|
205
201
|
# We can define the actual data we are ingesting here
|
|
206
202
|
# This mirrors the `uint8_t enabledSensors[5]` data
|
|
@@ -286,15 +282,13 @@ struct LEDS {
|
|
|
286
282
|
```
|
|
287
283
|
|
|
288
284
|
```python
|
|
289
|
-
@struct_dataclass
|
|
290
285
|
class RGB(StructDataclass):
|
|
291
286
|
r: uint8_t
|
|
292
287
|
g: uint8_t
|
|
293
288
|
b: uint8_t
|
|
294
289
|
|
|
295
|
-
@struct_dataclass
|
|
296
290
|
class LEDS(StructDataclass):
|
|
297
|
-
lights: Annotated[list[RGB], TypeMeta(size=3
|
|
291
|
+
lights: Annotated[list[RGB], TypeMeta(size=3)]
|
|
298
292
|
|
|
299
293
|
l = LEDS()
|
|
300
294
|
l.decode([1, 2, 3, 4, 5, 6, 7, 8, 9])
|
|
@@ -310,4 +304,4 @@ l.decode([1, 2, 3, 4, 5, 6, 7, 8, 9])
|
|
|
310
304
|
|
|
311
305
|
# Examples
|
|
312
306
|
|
|
313
|
-
You can see a more fully fledged example in the `test/examples.py` file.
|
|
307
|
+
You can see a more fully fledged example in the `test/examples.py` file.
|
|
@@ -34,7 +34,6 @@ struct MyStruct {
|
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
```python
|
|
37
|
-
@struct_dataclass
|
|
38
37
|
class MyStruct(StructDataclass):
|
|
39
38
|
myNum: int16_t
|
|
40
39
|
myLetter: char_t
|
|
@@ -61,7 +60,6 @@ struct MyStruct {
|
|
|
61
60
|
};
|
|
62
61
|
```
|
|
63
62
|
```python
|
|
64
|
-
@struct_dataclass
|
|
65
63
|
class MyStruct(StructDataclass):
|
|
66
64
|
myInts: Annotated[list[uint8_t], TypeMeta(size=4)]
|
|
67
65
|
myBiggerInts: Annotated[list[uint16_t], TypeMeta(size=2)]
|
|
@@ -87,7 +85,6 @@ struct MyStruct {
|
|
|
87
85
|
```
|
|
88
86
|
|
|
89
87
|
```python
|
|
90
|
-
@struct_dataclass
|
|
91
88
|
class MyStruct(StructDataclass):
|
|
92
89
|
myInt: uint8_t = 5
|
|
93
90
|
myInts: Annnotated[list[uint8_t], TypeMeta(size=2, default=1)]
|
|
@@ -117,7 +114,6 @@ struct MyStruct {
|
|
|
117
114
|
};
|
|
118
115
|
```
|
|
119
116
|
```python
|
|
120
|
-
@struct_dataclass
|
|
121
117
|
class MyStruct(StructDataclass):
|
|
122
118
|
myStr: Annotated[string_t, TypeMeta[str](chunk_size=3)]
|
|
123
119
|
myStrList: Annotated[list[string_t], TypeMeta[str](size=2, chunk_size=3)]
|
|
@@ -147,8 +143,9 @@ enum ConfigFlags {
|
|
|
147
143
|
```
|
|
148
144
|
|
|
149
145
|
```python
|
|
150
|
-
|
|
151
|
-
|
|
146
|
+
class FlagsType(BitsType):
|
|
147
|
+
__bits_type__ = uint8_t
|
|
148
|
+
__bits_definition__ = {"lights_flag": 0, "platform_flag": 1}
|
|
152
149
|
|
|
153
150
|
f = FlagsType()
|
|
154
151
|
f.decode([3])
|
|
@@ -178,7 +175,6 @@ struct MyStruct {
|
|
|
178
175
|
```
|
|
179
176
|
|
|
180
177
|
```python
|
|
181
|
-
@struct_dataclass
|
|
182
178
|
class EnabledSensors(StructDataclass):
|
|
183
179
|
# We can define the actual data we are ingesting here
|
|
184
180
|
# This mirrors the `uint8_t enabledSensors[5]` data
|
|
@@ -264,15 +260,13 @@ struct LEDS {
|
|
|
264
260
|
```
|
|
265
261
|
|
|
266
262
|
```python
|
|
267
|
-
@struct_dataclass
|
|
268
263
|
class RGB(StructDataclass):
|
|
269
264
|
r: uint8_t
|
|
270
265
|
g: uint8_t
|
|
271
266
|
b: uint8_t
|
|
272
267
|
|
|
273
|
-
@struct_dataclass
|
|
274
268
|
class LEDS(StructDataclass):
|
|
275
|
-
lights: Annotated[list[RGB], TypeMeta(size=3
|
|
269
|
+
lights: Annotated[list[RGB], TypeMeta(size=3)]
|
|
276
270
|
|
|
277
271
|
l = LEDS()
|
|
278
272
|
l.decode([1, 2, 3, 4, 5, 6, 7, 8, 9])
|
|
@@ -288,4 +282,4 @@ l.decode([1, 2, 3, 4, 5, 6, 7, 8, 9])
|
|
|
288
282
|
|
|
289
283
|
# Examples
|
|
290
284
|
|
|
291
|
-
You can see a more fully fledged example in the `test/examples.py` file.
|
|
285
|
+
You can see a more fully fledged example in the `test/examples.py` file.
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import tomllib
|
|
2
2
|
from datetime import datetime
|
|
3
3
|
|
|
4
|
+
from sphinx.application import Sphinx
|
|
5
|
+
|
|
4
6
|
# Sphinx Base --------------------------------------------------------------------------
|
|
5
7
|
# Extensions
|
|
6
8
|
extensions = [
|
|
@@ -61,7 +63,7 @@ exclude_patterns = ["autoapi_templates"]
|
|
|
61
63
|
|
|
62
64
|
|
|
63
65
|
# Add any Sphinx plugin settings here that don't have global variables exposed.
|
|
64
|
-
def setup(app):
|
|
66
|
+
def setup(app: Sphinx) -> None:
|
|
65
67
|
# App Settings ---------------------------------------------------------------------
|
|
66
68
|
# Set source filetype(s)
|
|
67
69
|
# Allow .rst files
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pystructtype"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.4.0"
|
|
4
4
|
description = "Leverage Python Types to Define C-Struct Interfaces"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [{name = "fchorney", email = "github@djsbx.com"}]
|
|
@@ -13,10 +13,10 @@ classifiers = [
|
|
|
13
13
|
"Operating System :: OS Independent",
|
|
14
14
|
"Intended Audience :: Developers",
|
|
15
15
|
"Topic :: Utilities",
|
|
16
|
-
"Programming Language :: Python :: 3.
|
|
16
|
+
"Programming Language :: Python :: 3.14",
|
|
17
17
|
]
|
|
18
18
|
keywords = ["struct", "cstruct", "type"]
|
|
19
|
-
requires-python = ">=3.
|
|
19
|
+
requires-python = ">=3.14,<4.0"
|
|
20
20
|
dependencies = []
|
|
21
21
|
|
|
22
22
|
[project.urls]
|
|
@@ -27,22 +27,28 @@ Issues = "https://github.com/fchorney/pystructtype/issues"
|
|
|
27
27
|
|
|
28
28
|
[dependency-groups]
|
|
29
29
|
dev = [
|
|
30
|
-
"coverage[toml]",
|
|
31
|
-
"mypy",
|
|
32
|
-
"
|
|
33
|
-
"pytest
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"sphinx
|
|
37
|
-
"sphinx-
|
|
38
|
-
"
|
|
39
|
-
"tox
|
|
30
|
+
"coverage[toml]>=7.6.12",
|
|
31
|
+
"mypy>=1.19.1",
|
|
32
|
+
"pre-commit>=4.5.1",
|
|
33
|
+
"pytest>=9.0.2",
|
|
34
|
+
"pytest-cov>=6.3.0",
|
|
35
|
+
"ruff>=0.15.6",
|
|
36
|
+
"sphinx>=9.1.0",
|
|
37
|
+
"sphinx-autoapi>=3.8.0",
|
|
38
|
+
"sphinx-rtd-theme>=3.1.0",
|
|
39
|
+
"tox>=4.49.1",
|
|
40
|
+
"tox-uv>=1.33.4",
|
|
40
41
|
]
|
|
41
42
|
|
|
42
43
|
[build-system]
|
|
43
44
|
requires = ["hatchling"]
|
|
44
45
|
build-backend = "hatchling.build"
|
|
45
46
|
|
|
47
|
+
[tool.mypy]
|
|
48
|
+
strict = false
|
|
49
|
+
check_untyped_defs = true
|
|
50
|
+
exclude = ["venv", ".venv"]
|
|
51
|
+
|
|
46
52
|
[tool.coverage.run]
|
|
47
53
|
relative_files = true
|
|
48
54
|
|
|
@@ -56,30 +62,39 @@ exclude_lines = ["if __name__ == .__main__.:", "def __str__", "def __repr__", "p
|
|
|
56
62
|
package = true
|
|
57
63
|
|
|
58
64
|
[tool.ruff]
|
|
65
|
+
target-version = "py314"
|
|
59
66
|
line-length = 120
|
|
60
67
|
indent-width = 4
|
|
61
|
-
|
|
62
|
-
target-version = "py313"
|
|
68
|
+
exclude = []
|
|
63
69
|
|
|
64
70
|
[tool.ruff.lint]
|
|
65
71
|
select = [
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
72
|
+
"E", # pycodestyle errors
|
|
73
|
+
"W", # pycodestyle warnings
|
|
74
|
+
"F", # pyflakes
|
|
75
|
+
"I", # isort
|
|
76
|
+
"N", # pep8-naming
|
|
77
|
+
"B", # flake8-bugbear
|
|
78
|
+
"C4", # flake8-comprehensions
|
|
79
|
+
"UP", # pyupgrade
|
|
80
|
+
"ARG001", # unused arguments in functions
|
|
81
|
+
"RUF", # ruff specific rules
|
|
82
|
+
]
|
|
83
|
+
ignore = [
|
|
84
|
+
"B008", # do not perform function calls in argument defaults
|
|
85
|
+
"W191", # indentation contains tabs
|
|
73
86
|
]
|
|
74
|
-
ignore = []
|
|
75
87
|
fixable = ["ALL"]
|
|
76
88
|
unfixable = []
|
|
77
89
|
|
|
78
90
|
[tool.ruff.format]
|
|
79
|
-
# Like Black
|
|
80
91
|
quote-style = "double"
|
|
81
92
|
indent-style = "space"
|
|
82
93
|
skip-magic-trailing-comma = false
|
|
83
94
|
line-ending = "auto"
|
|
84
95
|
docstring-code-format = true
|
|
85
96
|
docstring-code-line-length = "dynamic"
|
|
97
|
+
|
|
98
|
+
[tool.ruff.lint.pyupgrade]
|
|
99
|
+
# Preserve types, even if a file imports `from __future__ import annotations`.
|
|
100
|
+
keep-runtime-typing = true
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
from pystructtype.bitstype import BitsType
|
|
2
|
-
from pystructtype.structdataclass import StructDataclass
|
|
1
|
+
from pystructtype.bitstype import BitsType
|
|
2
|
+
from pystructtype.structdataclass import StructDataclass
|
|
3
3
|
from pystructtype.structtypes import (
|
|
4
4
|
TypeInfo,
|
|
5
5
|
TypeMeta,
|
|
@@ -22,7 +22,6 @@ __all__ = [
|
|
|
22
22
|
"StructDataclass",
|
|
23
23
|
"TypeInfo",
|
|
24
24
|
"TypeMeta",
|
|
25
|
-
"bits",
|
|
26
25
|
"char_t",
|
|
27
26
|
"double_t",
|
|
28
27
|
"float_t",
|
|
@@ -31,7 +30,6 @@ __all__ = [
|
|
|
31
30
|
"int32_t",
|
|
32
31
|
"int64_t",
|
|
33
32
|
"string_t",
|
|
34
|
-
"struct_dataclass",
|
|
35
33
|
"uint8_t",
|
|
36
34
|
"uint16_t",
|
|
37
35
|
"uint32_t",
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
from collections.abc import Mapping
|
|
3
|
+
from dataclasses import field
|
|
4
|
+
from types import MappingProxyType
|
|
5
|
+
from typing import Annotated, ClassVar
|
|
6
|
+
|
|
7
|
+
from pystructtype.structdataclass import StructDataclass
|
|
8
|
+
from pystructtype.structtypes import TypeMeta
|
|
9
|
+
from pystructtype.utils import int_to_bool_list
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BitsType(StructDataclass):
|
|
13
|
+
"""
|
|
14
|
+
Base class for bitfield structs. Subclasses must define __bits_type__ and __bits_definition__.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
__bits_type__: ClassVar[type]
|
|
18
|
+
__bits_definition__: ClassVar[dict[str, int | list[int]] | Mapping[str, int | list[int]]]
|
|
19
|
+
|
|
20
|
+
_raw: int
|
|
21
|
+
_meta: dict[str, int | list[int]]
|
|
22
|
+
|
|
23
|
+
def __init_subclass__(cls, **kwargs):
|
|
24
|
+
super().__init_subclass__(**kwargs)
|
|
25
|
+
# Check for required attributes
|
|
26
|
+
if not hasattr(cls, "__bits_type__") or not hasattr(cls, "__bits_definition__"):
|
|
27
|
+
raise TypeError(
|
|
28
|
+
"Subclasses of BitsType must define __bits_type__ and __bits_definition__ class attributes."
|
|
29
|
+
)
|
|
30
|
+
bits_type = cls.__bits_type__
|
|
31
|
+
definition = cls.__bits_definition__
|
|
32
|
+
|
|
33
|
+
# Automatically wrap in MappingProxyType if it's a dict and not already immutable
|
|
34
|
+
if isinstance(definition, dict) and not isinstance(definition, MappingProxyType):
|
|
35
|
+
definition = MappingProxyType(definition)
|
|
36
|
+
cls.__bits_definition__ = definition
|
|
37
|
+
|
|
38
|
+
# # Remove __bits_type__ and __bits_definition__ from __annotations__ if present
|
|
39
|
+
# cls.__annotations__.pop("__bits_type__", None)
|
|
40
|
+
# cls.__annotations__.pop("__bits_definition__", None)
|
|
41
|
+
|
|
42
|
+
# Set the correct type for the raw data
|
|
43
|
+
cls._raw = 0
|
|
44
|
+
cls.__annotations__["_raw"] = bits_type
|
|
45
|
+
|
|
46
|
+
cls._meta = field(default_factory=dict)
|
|
47
|
+
|
|
48
|
+
# Create the defined attributes, defaults, and annotations in the class
|
|
49
|
+
for key, value in definition.items():
|
|
50
|
+
if isinstance(value, list):
|
|
51
|
+
setattr(
|
|
52
|
+
cls,
|
|
53
|
+
key,
|
|
54
|
+
field(default_factory=lambda v=len(value): [False for _ in range(v)]), # type: ignore
|
|
55
|
+
)
|
|
56
|
+
cls.__annotations__[key] = Annotated[list[bool], TypeMeta(size=len(value))]
|
|
57
|
+
else:
|
|
58
|
+
setattr(cls, key, False)
|
|
59
|
+
cls.__annotations__[key] = bool
|
|
60
|
+
|
|
61
|
+
def __post_init__(self) -> None:
|
|
62
|
+
super().__post_init__()
|
|
63
|
+
self._meta = dict(self.__bits_definition__)
|
|
64
|
+
|
|
65
|
+
def _decode(self, data: list[int]) -> None:
|
|
66
|
+
super()._decode(data)
|
|
67
|
+
bin_data = int_to_bool_list(self._raw, self._byte_length)
|
|
68
|
+
for k, v in self._meta.items():
|
|
69
|
+
if isinstance(v, list):
|
|
70
|
+
steps = [bin_data[idx] for idx in v]
|
|
71
|
+
setattr(self, k, steps)
|
|
72
|
+
else:
|
|
73
|
+
setattr(self, k, bin_data[v])
|
|
74
|
+
|
|
75
|
+
def _encode(self) -> list[int]:
|
|
76
|
+
bin_data = list(itertools.repeat(False, self._byte_length * 8))
|
|
77
|
+
for k, v in self._meta.items():
|
|
78
|
+
if isinstance(v, list):
|
|
79
|
+
steps = getattr(self, k)
|
|
80
|
+
for idx, bit_idx in enumerate(v):
|
|
81
|
+
bin_data[bit_idx] = steps[idx]
|
|
82
|
+
else:
|
|
83
|
+
bin_data[v] = getattr(self, k)
|
|
84
|
+
self._raw = sum(int(v) << i for i, v in enumerate(bin_data))
|
|
85
|
+
# Return _raw as a list of bytes (little-endian)
|
|
86
|
+
return super()._encode()
|