diff --git a/binmap/__init__.py b/binmap/__init__.py index e77c84e..908f1b1 100644 --- a/binmap/__init__.py +++ b/binmap/__init__.py @@ -178,6 +178,12 @@ def enumfield( return dataclasses.field(default=default, metadata={"enum": enumclass}) + """ + Field generator function for calculated fields + + :param Callable function: function that calculates the field. + :return: dataclass field + """ def calculatedfield(function: Callable) -> dataclasses.Field: return dataclasses.field(default=0, metadata={"function": function}) @@ -285,5 +291,8 @@ def frombytes(self, value: bytes): elif "autolength" in self.__datafieldsmap[name].metadata: if arg != getattr(self, name): raise ValueError("Length doesn't match") + elif "function" in self.__datafieldsmap[name].metadata: + if arg != self.__datafieldsmap[name].metadata["function"](self): + raise ValueError("Wrong calculated value") else: setattr(self, name, arg) diff --git a/tests/test_binmap.py b/tests/test_binmap.py index f9cac2f..0d3e46e 100644 --- a/tests/test_binmap.py +++ b/tests/test_binmap.py @@ -596,7 +596,7 @@ class CalculatedField(binmap.BinmapDataclass): temp: types.signedchar = 0 hum: types.unsignedchar = 0 - def chk(self): + def chk(self) -> types.unsignedchar: return (self.temp + self.hum) & 0xFF checksum: types.unsignedchar = binmap.calculatedfield(chk) @@ -610,3 +610,13 @@ def test_calculated_field(self): assert cf.checksum == 239 assert bytes(cf) == b"\xe5\x0a\xef" + + def test_calculated_field_binary(self): + cf = CalculatedField(b"\xe2\x12\xf4") + assert cf.temp == -30 + assert cf.hum == 18 + assert cf.checksum == 244 + + with pytest.raises(ValueError) as excinfo: + CalculatedField(b"\xe4\x18\x00") + assert "Wrong calculated value" in str(excinfo)