sltcodec 2.5.1__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sltcodec
3
- Version: 2.5.1
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sltcodec"
3
- version = "2.5.1"
3
+ version = "2.6.0"
4
4
  description = "Decode and encode bytearrays according to struct layout definitions using sltcore."
5
5
  readme = "README_pypi.md"
6
6
  requires-python = ">=3.12"
@@ -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) -> 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: dict[str, Any] = {}
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: dict[str, Any] = {}
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 = [
@@ -74,7 +74,7 @@ wheels = [
74
74
 
75
75
  [[package]]
76
76
  name = "sltcodec"
77
- version = "2.5.0"
77
+ version = "2.5.1"
78
78
  source = { editable = "." }
79
79
  dependencies = [
80
80
  { name = "sltcalc" },
@@ -89,7 +89,7 @@ dev = [
89
89
  [package.metadata]
90
90
  requires-dist = [
91
91
  { name = "sltcalc", specifier = ">=1.0.0" },
92
- { name = "sltcore", specifier = ">=1.6.0" },
92
+ { name = "sltcore", specifier = ">=1.7.0" },
93
93
  ]
94
94
 
95
95
  [package.metadata.requires-dev]
@@ -97,9 +97,9 @@ dev = [{ name = "pytest", specifier = ">=9.1.1" }]
97
97
 
98
98
  [[package]]
99
99
  name = "sltcore"
100
- version = "1.6.0"
100
+ version = "1.7.0"
101
101
  source = { registry = "https://pypi.org/simple" }
102
- sdist = { url = "https://files.pythonhosted.org/packages/32/01/89dc1e6c0429710d7329a3dab769e1c9f8b148ab1592c69df53592dbf8c2/sltcore-1.6.0.tar.gz", hash = "sha256:872ada7183ae5f065a40dc44ee5062bb7cc781a4758b56cd740bb77e9e1fdc6e", size = 20648, upload-time = "2026-08-21T14:49:00.72Z" }
102
+ sdist = { url = "https://files.pythonhosted.org/packages/d9/04/738d61e4b374fdf933e4f1c58e1f7f5c667bdde4d469daf7cce7abe0deaf/sltcore-1.7.0.tar.gz", hash = "sha256:fb0cd43a144d5fbcd48c83e47b1b9cf28718528e8594211bf8985a1423656888", size = 21378, upload-time = "2026-08-22T07:57:51.456Z" }
103
103
  wheels = [
104
- { url = "https://files.pythonhosted.org/packages/a4/b5/d35ac0fcab3a16efdc80814a59d1788a962e8ac8d8005dc6c18435baf655/sltcore-1.6.0-py3-none-any.whl", hash = "sha256:d3bf525275fda9159b97c2663d14bb73b56b70869e07f0d79727883bcbedd8d8", size = 12707, upload-time = "2026-08-21T14:48:59.749Z" },
104
+ { url = "https://files.pythonhosted.org/packages/0f/75/41f5189ba217d4d4a60050d7302e9aeb95f2ddb8aa6849d8545c56062dff/sltcore-1.7.0-py3-none-any.whl", hash = "sha256:bbd692d12358019cc5625010351f7b0ea9948fca5fea7c2ac37d62f9bcb9309b", size = 13236, upload-time = "2026-08-22T07:57:50.43Z" },
105
105
  ]
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