sltcodec 2.5.2__tar.gz → 2.6.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.
- {sltcodec-2.5.2 → sltcodec-2.6.0}/PKG-INFO +8 -3
- {sltcodec-2.5.2 → sltcodec-2.6.0}/README.md +5 -0
- {sltcodec-2.5.2 → sltcodec-2.6.0}/README_pypi.md +7 -2
- {sltcodec-2.5.2 → sltcodec-2.6.0}/pyproject.toml +1 -1
- {sltcodec-2.5.2 → sltcodec-2.6.0}/src/sltcodec/codec.py +14 -6
- {sltcodec-2.5.2 → sltcodec-2.6.0}/tests/test_codec.py +31 -0
- {sltcodec-2.5.2 → sltcodec-2.6.0}/.github/workflows/publish_to_pypi.yml +0 -0
- {sltcodec-2.5.2 → sltcodec-2.6.0}/.github/workflows/publish_to_testpypi.yml +0 -0
- {sltcodec-2.5.2 → sltcodec-2.6.0}/.gitignore +0 -0
- {sltcodec-2.5.2 → sltcodec-2.6.0}/.python-version +0 -0
- {sltcodec-2.5.2 → sltcodec-2.6.0}/.vscode/launch.json +0 -0
- {sltcodec-2.5.2 → sltcodec-2.6.0}/.vscode/settings.json +0 -0
- {sltcodec-2.5.2 → sltcodec-2.6.0}/LICENSE +0 -0
- {sltcodec-2.5.2 → sltcodec-2.6.0}/bump_major.ps1 +0 -0
- {sltcodec-2.5.2 → sltcodec-2.6.0}/bump_minor.ps1 +0 -0
- {sltcodec-2.5.2 → sltcodec-2.6.0}/bump_patch.ps1 +0 -0
- {sltcodec-2.5.2 → sltcodec-2.6.0}/src/sltcodec/__init__.py +0 -0
- {sltcodec-2.5.2 → sltcodec-2.6.0}/src/sltcodec/types.py +0 -0
- {sltcodec-2.5.2 → sltcodec-2.6.0}/tests/test_persistence.py +0 -0
- {sltcodec-2.5.2 → sltcodec-2.6.0}/tests/test_types.py +0 -0
- {sltcodec-2.5.2 → sltcodec-2.6.0}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sltcodec
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.6.0
|
|
4
4
|
Summary: Decode and encode bytearrays according to struct layout definitions using sltcore.
|
|
5
5
|
Project-URL: Homepage, https://github.com/fangface-hub/StructLayoutToolkitCodec
|
|
6
6
|
Project-URL: Documentation, https://readthedocs.org
|
|
@@ -73,6 +73,11 @@ Progress is calculated for top-level fields as `(offset + size) / total_size`.
|
|
|
73
73
|
Nested structure encode/decode calls pass `None` internally, so recursive
|
|
74
74
|
fields do not emit additional callback events.
|
|
75
75
|
|
|
76
|
+
`encode` and `decode` also accept an optional `env` dictionary for evaluating
|
|
77
|
+
expression-based field definitions. The default is `None`, which uses an empty
|
|
78
|
+
environment. The same environment is passed to recursive nested structure
|
|
79
|
+
encode and decode calls.
|
|
80
|
+
|
|
76
81
|
```python
|
|
77
82
|
from sltcodec import ProgressCallback, decode
|
|
78
83
|
|
|
@@ -338,9 +343,9 @@ beginning with `_` are internal helpers and are not part of the public API.
|
|
|
338
343
|
| `load_struct_def_dict` | `(path) -> dict[str, StructDef]` | Load a structure-definition dictionary. |
|
|
339
344
|
| `save_enum_def_dict` | `(path, enum_def_dict) -> None` | Save an enum-definition dictionary through the layout format. |
|
|
340
345
|
| `load_enum_def_dict` | `(path) -> dict[str, EnumDef]` | Load an enum-definition dictionary. |
|
|
341
|
-
| `encode` | `(struct_layout, struct_instance, buf, padding_alignment_bits=32, progress_callback=None) -> bytearray` | Encode a complete structure. |
|
|
346
|
+
| `encode` | `(struct_layout, struct_instance, buf, padding_alignment_bits=32, progress_callback=None, env=None) -> bytearray` | Encode a complete structure. `env` provides values for expression evaluation and is inherited by nested encodes. |
|
|
342
347
|
| `decode_field` | `(field_def, data, env=None, type_dict=None, padding_alignment_bits=32) -> FieldInstance \| None` | Decode one field. |
|
|
343
|
-
| `decode` | `(struct_layout, data, padding_alignment_bits=32, progress_callback=None) -> StructInstance` | Decode a complete structure. |
|
|
348
|
+
| `decode` | `(struct_layout, data, padding_alignment_bits=32, progress_callback=None, env=None) -> StructInstance` | Decode a complete structure. `env` provides values for expression evaluation and is inherited by nested decodes. |
|
|
344
349
|
|
|
345
350
|
`save_struct_def_dict`, `load_struct_def_dict`, `save_enum_def_dict`, and
|
|
346
351
|
`load_enum_def_dict` are available from `sltcodec.codec` for dictionary-level
|
|
@@ -63,6 +63,11 @@ from the top-level field extent: `(offset + size) / total_size`. Recursive
|
|
|
63
63
|
nested structure calls pass `None`, so callers receive progress updates only
|
|
64
64
|
for the top-level encode or decode operation.
|
|
65
65
|
|
|
66
|
+
`encode` and `decode` also accept an optional `env` dictionary for evaluating
|
|
67
|
+
expression-based field definitions. The default is `None`, which uses an empty
|
|
68
|
+
environment. The same environment is passed to recursive nested structure
|
|
69
|
+
encode and decode calls.
|
|
70
|
+
|
|
66
71
|
```python
|
|
67
72
|
from sltcodec import ProgressCallback, decode
|
|
68
73
|
|
|
@@ -56,6 +56,11 @@ Progress is calculated for top-level fields as `(offset + size) / total_size`.
|
|
|
56
56
|
Nested structure encode/decode calls pass `None` internally, so recursive
|
|
57
57
|
fields do not emit additional callback events.
|
|
58
58
|
|
|
59
|
+
`encode` and `decode` also accept an optional `env` dictionary for evaluating
|
|
60
|
+
expression-based field definitions. The default is `None`, which uses an empty
|
|
61
|
+
environment. The same environment is passed to recursive nested structure
|
|
62
|
+
encode and decode calls.
|
|
63
|
+
|
|
59
64
|
```python
|
|
60
65
|
from sltcodec import ProgressCallback, decode
|
|
61
66
|
|
|
@@ -321,9 +326,9 @@ beginning with `_` are internal helpers and are not part of the public API.
|
|
|
321
326
|
| `load_struct_def_dict` | `(path) -> dict[str, StructDef]` | Load a structure-definition dictionary. |
|
|
322
327
|
| `save_enum_def_dict` | `(path, enum_def_dict) -> None` | Save an enum-definition dictionary through the layout format. |
|
|
323
328
|
| `load_enum_def_dict` | `(path) -> dict[str, EnumDef]` | Load an enum-definition dictionary. |
|
|
324
|
-
| `encode` | `(struct_layout, struct_instance, buf, padding_alignment_bits=32, progress_callback=None) -> bytearray` | Encode a complete structure. |
|
|
329
|
+
| `encode` | `(struct_layout, struct_instance, buf, padding_alignment_bits=32, progress_callback=None, env=None) -> bytearray` | Encode a complete structure. `env` provides values for expression evaluation and is inherited by nested encodes. |
|
|
325
330
|
| `decode_field` | `(field_def, data, env=None, type_dict=None, padding_alignment_bits=32) -> FieldInstance \| None` | Decode one field. |
|
|
326
|
-
| `decode` | `(struct_layout, data, padding_alignment_bits=32, progress_callback=None) -> StructInstance` | Decode a complete structure. |
|
|
331
|
+
| `decode` | `(struct_layout, data, padding_alignment_bits=32, progress_callback=None, env=None) -> StructInstance` | Decode a complete structure. `env` provides values for expression evaluation and is inherited by nested decodes. |
|
|
327
332
|
|
|
328
333
|
`save_struct_def_dict`, `load_struct_def_dict`, `save_enum_def_dict`, and
|
|
329
334
|
`load_enum_def_dict` are available from `sltcodec.codec` for dictionary-level
|
|
@@ -40,9 +40,10 @@ def _notify_progress(progress_callback: ProgressCallback | None,
|
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
def _estimate_encode_total_bits(struct_instance: StructInstance,
|
|
43
|
-
initial_size_bits: int
|
|
43
|
+
initial_size_bits: int,
|
|
44
|
+
env: dict[str, Any] | None = None) -> int:
|
|
44
45
|
"""Estimate encoded top-level extent before mutating the output buffer."""
|
|
45
|
-
env
|
|
46
|
+
env = dict(env) if env is not None else {}
|
|
46
47
|
total_bits = max(struct_instance.size.bits, initial_size_bits)
|
|
47
48
|
|
|
48
49
|
for field_value in struct_instance.field_instances:
|
|
@@ -309,7 +310,7 @@ def _prepare_field_info(
|
|
|
309
310
|
_layout_for_struct_def(value.struct_def,
|
|
310
311
|
type_dict,
|
|
311
312
|
name=field_def.name), value, bytearray(),
|
|
312
|
-
padding_alignment_bits, None)
|
|
313
|
+
padding_alignment_bits, None, env)
|
|
313
314
|
info = Info.from_bytes(bytes(nested_bytes), size, scale=field_def.scale)
|
|
314
315
|
else:
|
|
315
316
|
info = _encode_primitive(resolved_type, value, size, field_def.scale)
|
|
@@ -375,6 +376,7 @@ def encode(
|
|
|
375
376
|
buf: bytearray,
|
|
376
377
|
padding_alignment_bits: int = _DEFAULT_PADDING_ALIGNMENT_BITS,
|
|
377
378
|
progress_callback: ProgressCallback | None = None,
|
|
379
|
+
env: dict[str, Any] | None = None,
|
|
378
380
|
) -> bytearray:
|
|
379
381
|
"""Encode decode() result into a bytearray.
|
|
380
382
|
|
|
@@ -392,6 +394,8 @@ def encode(
|
|
|
392
394
|
progress_callback : Callable[[float], None] | None, optional
|
|
393
395
|
Called after each top-level field is encoded with progress in the
|
|
394
396
|
range 0.0 to 1.0. Nested recursive encodes are skipped.
|
|
397
|
+
env : dict[str, Any] | None, optional
|
|
398
|
+
The environment for evaluating expressions, by default None.
|
|
395
399
|
|
|
396
400
|
Returns
|
|
397
401
|
-------
|
|
@@ -406,9 +410,9 @@ def encode(
|
|
|
406
410
|
raise ValueError("StructLayout.type_dict is required for encode()")
|
|
407
411
|
|
|
408
412
|
type_dict = struct_layout.type_dict
|
|
409
|
-
env
|
|
413
|
+
env = env if env is not None else {}
|
|
410
414
|
has_padding = False
|
|
411
|
-
total_bits = _estimate_encode_total_bits(struct_instance, len(buf) * 8)
|
|
415
|
+
total_bits = _estimate_encode_total_bits(struct_instance, len(buf) * 8, env)
|
|
412
416
|
|
|
413
417
|
for field_value in struct_instance.field_instances:
|
|
414
418
|
field_def = field_value.field_def
|
|
@@ -504,6 +508,7 @@ def decode_field(
|
|
|
504
508
|
nested_data,
|
|
505
509
|
padding_alignment_bits,
|
|
506
510
|
None,
|
|
511
|
+
env,
|
|
507
512
|
)
|
|
508
513
|
actual_size = nested_value.size
|
|
509
514
|
else:
|
|
@@ -574,6 +579,7 @@ def decode(
|
|
|
574
579
|
data: bytearray | bytes,
|
|
575
580
|
padding_alignment_bits: int = _DEFAULT_PADDING_ALIGNMENT_BITS,
|
|
576
581
|
progress_callback: ProgressCallback | None = None,
|
|
582
|
+
env: dict[str, Any] | None = None,
|
|
577
583
|
) -> StructInstance:
|
|
578
584
|
"""Decode a bytearray into field values according to a layout.
|
|
579
585
|
|
|
@@ -589,6 +595,8 @@ def decode(
|
|
|
589
595
|
progress_callback : Callable[[float], None] | None, optional
|
|
590
596
|
Called after each top-level field is decoded with progress in the
|
|
591
597
|
range 0.0 to 1.0. Nested recursive decodes are skipped.
|
|
598
|
+
env : dict[str, Any] | None, optional
|
|
599
|
+
The environment for evaluating expressions, by default None.
|
|
592
600
|
Returns
|
|
593
601
|
-------
|
|
594
602
|
StructInstance
|
|
@@ -600,7 +608,7 @@ def decode(
|
|
|
600
608
|
if struct_layout.type_dict is None:
|
|
601
609
|
raise ValueError("StructLayout.type_dict is required for decode()")
|
|
602
610
|
|
|
603
|
-
env = {}
|
|
611
|
+
env = env if env is not None else {}
|
|
604
612
|
type_dict = struct_layout.type_dict
|
|
605
613
|
struct_def_obj = type_dict.struct_dict[struct_layout.struct_def_name]
|
|
606
614
|
result = StructInstance(struct_def=struct_def_obj)
|
|
@@ -435,6 +435,37 @@ def test_encode_recurses_for_nested_field_types():
|
|
|
435
435
|
]
|
|
436
436
|
|
|
437
437
|
|
|
438
|
+
def test_env_is_used_and_inherited_by_nested_encode_and_decode():
|
|
439
|
+
"""Test that the supplied env is available to recursive calls."""
|
|
440
|
+
child_field = FieldDef(name="value",
|
|
441
|
+
offset=InfoSize(0, 0),
|
|
442
|
+
size="payload_size",
|
|
443
|
+
type="unsigned int")
|
|
444
|
+
parent_field = FieldDef(name="payload",
|
|
445
|
+
offset=InfoSize(0, 0),
|
|
446
|
+
size="payload_size",
|
|
447
|
+
type=StructDef(fields=[child_field]))
|
|
448
|
+
child_def = StructDef(fields=[child_field])
|
|
449
|
+
parent_def = StructDef(fields=[parent_field])
|
|
450
|
+
instance = StructInstance(
|
|
451
|
+
struct_def=child_def,
|
|
452
|
+
field_instances=[FieldInstance(child_field, 0x1234)],
|
|
453
|
+
)
|
|
454
|
+
parent_instance = StructInstance(
|
|
455
|
+
struct_def=parent_def,
|
|
456
|
+
field_instances=[FieldInstance(parent_field, instance)],
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
encoded = encode(layout_for(parent_def),
|
|
460
|
+
parent_instance,
|
|
461
|
+
bytearray(),
|
|
462
|
+
env={"payload_size": 2})
|
|
463
|
+
decoded = decode(layout_for(parent_def), encoded, env={"payload_size": 2})
|
|
464
|
+
|
|
465
|
+
assert encoded == bytearray(b"\x12\x34")
|
|
466
|
+
assert decoded.field_instances[0].value.field_instances[0].value == 0x1234
|
|
467
|
+
|
|
468
|
+
|
|
438
469
|
def test_progress_callbacks_skip_nested_recursive_fields():
|
|
439
470
|
"""Test nested recursive encode/decode calls do not report progress."""
|
|
440
471
|
child_field_defs = [
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|