diff --git a/src/dbus_fast/_private/marshaller.pxd b/src/dbus_fast/_private/marshaller.pxd index 2c5d28b..f87c389 100644 --- a/src/dbus_fast/_private/marshaller.pxd +++ b/src/dbus_fast/_private/marshaller.pxd @@ -72,7 +72,7 @@ cdef class Marshaller: written=cython.uint, i=cython.uint, ) - cdef unsigned int _write_struct(self, cython.list array, SignatureType type_) + cdef unsigned int _write_struct(self, object array, SignatureType type_) cpdef write_variant(self, Variant variant, SignatureType type_) diff --git a/src/dbus_fast/_private/marshaller.py b/src/dbus_fast/_private/marshaller.py index 9da8db8..ba94e96 100644 --- a/src/dbus_fast/_private/marshaller.py +++ b/src/dbus_fast/_private/marshaller.py @@ -136,10 +136,14 @@ class Marshaller: return written + array_len - def write_struct(self, array: List[Any], type_: SignatureType) -> int: + def write_struct( + self, array: Union[Tuple[Any], List[Any]], type_: SignatureType + ) -> int: return self._write_struct(array, type_) - def _write_struct(self, array: List[Any], type_: SignatureType) -> int: + def _write_struct( + self, array: Union[Tuple[Any], List[Any]], type_: SignatureType + ) -> int: written = self._align(8) for i, value in enumerate(array): written += self._write_single(type_.children[i], value) diff --git a/src/dbus_fast/service.py b/src/dbus_fast/service.py index a8fcc9c..ebfb9a1 100644 --- a/src/dbus_fast/service.py +++ b/src/dbus_fast/service.py @@ -516,9 +516,10 @@ class ServiceInterface: if out_len == 1: result = [result] else: - if type(result) is not list: + result_type = type(result) + if result_type is not list and result_type is not tuple: raise SignatureBodyMismatchError( - "Expected signal to return a list of arguments" + "Expected signal to return a list or tuple of arguments" ) if out_len != len(result): diff --git a/src/dbus_fast/signature.py b/src/dbus_fast/signature.py index 89f4c30..e6368a2 100644 --- a/src/dbus_fast/signature.py +++ b/src/dbus_fast/signature.py @@ -258,10 +258,9 @@ class SignatureType: child_type.verify(member) def _verify_struct(self, body: Any) -> None: - # TODO allow tuples - if not isinstance(body, list): + if not isinstance(body, (list, tuple)): raise SignatureBodyMismatchError( - f'DBus STRUCT type "(" must be Python type "list", got {type(body)}' + f'DBus STRUCT type "(" must be Python type "list" or "tuple", got {type(body)}' ) if len(body) != len(self.children): diff --git a/tests/test_marshaller.py b/tests/test_marshaller.py index ee8cd60..ac9076a 100644 --- a/tests/test_marshaller.py +++ b/tests/test_marshaller.py @@ -714,3 +714,29 @@ def test_unmarshall_multi_byte_string(): assert unmarshaller.message.signature == "as" unpacked = unpack_variants(message.body) assert unpacked == [["//doesntmatter/über"]] + + +def test_marshalling_struct_accepts_tuples(): + """Test marshalling a struct accepts tuples.""" + msg = Message( + path="/test", + member="test", + signature="(s)", + body=[(RaucState.GOOD,)], + ) + marshalled = msg._marshall(False) + unmarshalled_msg = Unmarshaller(io.BytesIO(marshalled)).unmarshall() + assert unpack_variants(unmarshalled_msg.body)[0] == [RaucState.GOOD.value] + + +def test_marshalling_struct_accepts_lists(): + """Test marshalling a struct accepts lists.""" + msg = Message( + path="/test", + member="test", + signature="(s)", + body=[[RaucState.GOOD]], + ) + marshalled = msg._marshall(False) + unmarshalled_msg = Unmarshaller(io.BytesIO(marshalled)).unmarshall() + assert unpack_variants(unmarshalled_msg.body)[0] == [RaucState.GOOD.value] diff --git a/tests/test_signature.py b/tests/test_signature.py index c8d7fe0..6446efe 100644 --- a/tests/test_signature.py +++ b/tests/test_signature.py @@ -231,3 +231,9 @@ def test_variant_signature_type(): with pytest.raises(SignatureBodyMismatchError): Variant(tree.types[0], "wrong") + + +def test_struct_accepts_tuples_or_lists(): + tree = SignatureTree("(s)") + tree.verify([("ok",)]) + tree.verify([["ok"]])