diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index c74a17dc..acd8393e 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -70,7 +70,7 @@ jobs: - run: | mk python-release owner=vkottler \ - repo=runtimepy version=2.1.2 + repo=runtimepy version=2.1.3 if: | matrix.python-version == '3.11' && matrix.system == 'ubuntu-latest' diff --git a/.pylintrc b/.pylintrc index be2a5a69..f84bb969 100644 --- a/.pylintrc +++ b/.pylintrc @@ -1,5 +1,5 @@ [DESIGN] -max-args=7 +max-args=8 max-attributes=12 max-parents=8 diff --git a/README.md b/README.md index ce3620a3..ac83de95 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,11 @@ ===================================== generator=datazen version=3.1.2 - hash=64a758df8095e218dce93935454221a7 + hash=6a75e29b42b1d2fa20b1373c2a8adc01 ===================================== --> -# runtimepy ([2.1.2](https://pypi.org/project/runtimepy/)) +# runtimepy ([2.1.3](https://pypi.org/project/runtimepy/)) [![python](https://img.shields.io/pypi/pyversions/runtimepy.svg)](https://pypi.org/project/runtimepy/) ![Build Status](https://github.com/vkottler/runtimepy/workflows/Python%20Package/badge.svg) diff --git a/local/variables/package.yaml b/local/variables/package.yaml index 0841c680..254e6e35 100644 --- a/local/variables/package.yaml +++ b/local/variables/package.yaml @@ -1,5 +1,5 @@ --- major: 2 minor: 1 -patch: 2 +patch: 3 entry: runtimepy diff --git a/pyproject.toml b/pyproject.toml index 40377b50..0714556e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta:__legacy__" [project] name = "runtimepy" -version = "2.1.2" +version = "2.1.3" description = "A framework for implementing Python services." readme = "README.md" requires-python = ">=3.8" diff --git a/runtimepy/__init__.py b/runtimepy/__init__.py index f7744741..118eb9dd 100644 --- a/runtimepy/__init__.py +++ b/runtimepy/__init__.py @@ -1,7 +1,7 @@ # ===================================== # generator=datazen # version=3.1.2 -# hash=f83181278a252952c4fdf15493634816 +# hash=933cfe7057a94bf7e43e8b9938cb8159 # ===================================== """ @@ -10,4 +10,4 @@ DESCRIPTION = "A framework for implementing Python services." PKG_NAME = "runtimepy" -VERSION = "2.1.2" +VERSION = "2.1.3" diff --git a/runtimepy/codec/protocol/base.py b/runtimepy/codec/protocol/base.py index bea2fdfe..9a1361ed 100644 --- a/runtimepy/codec/protocol/base.py +++ b/runtimepy/codec/protocol/base.py @@ -29,6 +29,7 @@ from runtimepy.primitives.byte_order import ByteOrder as _ByteOrder from runtimepy.primitives.field.fields import BitFields as _BitFields from runtimepy.primitives.field.manager import BitFieldsManager +from runtimepy.primitives.serializable import Serializable, SerializableMap from runtimepy.registry.name import NameRegistry as _NameRegistry from runtimepy.registry.name import RegistryKey as _RegistryKey @@ -68,6 +69,7 @@ def __init__( build: _List[_Union[int, FieldSpec]] = None, identifier: int = 1, byte_order: _Union[_ByteOrder, _RegistryKey] = _DEFAULT_BYTE_ORDER, + serializables: SerializableMap = None, ) -> None: """Initialize this protocol.""" @@ -110,6 +112,12 @@ def __init__( item.name, item.kind, enum=item.enum, track=False ) + # Keep track of named serializables. + self.serializables: SerializableMap = {} + if serializables is not None: + for name, serializable in serializables.items(): + self.add_field(name, serializable=serializable) + def __copy__(self: T) -> T: """Create another protocol instance from this one.""" @@ -119,6 +127,7 @@ def __copy__(self: T) -> T: fields=_copy(self._fields), build=self._build, byte_order=self.array.byte_order, + serializables=self.serializables, ) def add_field( @@ -126,6 +135,7 @@ def add_field( name: str, kind: _Primitivelike = None, enum: _RegistryKey = None, + serializable: Serializable = None, track: bool = True, ) -> None: """Add a new field to the protocol.""" @@ -134,10 +144,21 @@ def add_field( ident = self._names.register_name(name) assert ident is not None, f"Couldn't register field '{name}'!" + # Add the serializable to the end of this protocol. + if serializable is not None: + assert kind is None and enum is None + self.serializables[name] = serializable + self.array.add_to_end(serializable) + return + if enum is not None: runtime_enum = self._enum_registry[enum] self._enum_fields[name] = runtime_enum - kind = runtime_enum.primitive + + # Allow the primitive type to be overridden when passed as a + # method argument. + if kind is None: + kind = runtime_enum.primitive assert kind is not None new = _create(kind) diff --git a/runtimepy/data/schemas/RuntimeEnum.yaml b/runtimepy/data/schemas/RuntimeEnum.yaml index 7bcb2a75..30d3f46c 100644 --- a/runtimepy/data/schemas/RuntimeEnum.yaml +++ b/runtimepy/data/schemas/RuntimeEnum.yaml @@ -23,5 +23,4 @@ properties: "^\\w+$": oneOf: - type: integer - minimum: 0 - type: boolean diff --git a/runtimepy/primitives/array/__init__.py b/runtimepy/primitives/array/__init__.py index 3e34a569..59f81f73 100644 --- a/runtimepy/primitives/array/__init__.py +++ b/runtimepy/primitives/array/__init__.py @@ -39,7 +39,7 @@ def __init__( *primitives: _AnyPrimitive, byte_order: _ByteOrder = _DEFAULT_BYTE_ORDER, fragments: _List[ArrayFragmentSpec] = None, - next_array: "PrimitiveArray" = None, + chain: Serializable = None, ) -> None: """Initialize this primitive array.""" @@ -59,7 +59,7 @@ def __init__( for item in primitives: self.add(item) - super().__init__(byte_order=self.byte_order, chain=next_array) + super().__init__(byte_order=self.byte_order, chain=chain) self._fragments: _List["PrimitiveArray"] = [] self._fragment_specs: _List[ArrayFragmentSpec] = [] diff --git a/runtimepy/primitives/serializable/__init__.py b/runtimepy/primitives/serializable/__init__.py index 803ffd15..4630386c 100644 --- a/runtimepy/primitives/serializable/__init__.py +++ b/runtimepy/primitives/serializable/__init__.py @@ -2,8 +2,13 @@ A module defining an interface for serializable objects. """ +# built-in +from typing import Dict + # internal from runtimepy.primitives.serializable.base import Serializable from runtimepy.primitives.serializable.fixed import FixedChunk +from runtimepy.primitives.serializable.prefixed import PrefixedChunk -__all__ = ["Serializable", "FixedChunk"] +SerializableMap = Dict[str, Serializable] +__all__ = ["Serializable", "SerializableMap", "FixedChunk", "PrefixedChunk"] diff --git a/tests/codec/test_protocol.py b/tests/codec/test_protocol.py index 2931cf2e..95a4074a 100644 --- a/tests/codec/test_protocol.py +++ b/tests/codec/test_protocol.py @@ -11,6 +11,7 @@ from runtimepy.codec.protocol import Protocol from runtimepy.codec.protocol.base import FieldSpec from runtimepy.enum.registry import EnumRegistry +from runtimepy.primitives.serializable import PrefixedChunk # internal from tests.resources import resource @@ -62,3 +63,16 @@ def test_protocol_basic(): assert Protocol.import_json(load(stream)) assert str(proto) + + # Create a string serializable. + string = PrefixedChunk.create() + assert string.length() == 2 + assert string.update_str("abc") == 5 + + # Add the string to the end and confirm the size update. + curr = proto.size + proto.add_field("string", serializable=string) + assert proto.size == curr + 5 + + # Should be the same size. + assert copy(proto).size == proto.size