From 3282eed607cb7f9f64a3275d1f9155c0e65bd8f8 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 2 Aug 2022 18:16:31 -1000 Subject: [PATCH 01/17] Improve unmarshall performance This change reduces the overhead of unmarshalling with the goal of having bleak scanners not overwhelming the system. See related issue: https://github.com/hbldh/bleak/issues/236#issuecomment-789055069 ``` (speed_up_unmarsh) % python3 bench/unmarshall.py Unmarshalling 1000000 bluetooth rssi messages took 14.397348250000505 seconds (master) % python3 bench/unmarshall.py Unmarshalling 1000000 bluetooth rssi messages took 47.7756206660124 seconds ``` --- bench/unmarshall.py | 22 ++ dbus_next/_private/constants.py | 5 + dbus_next/_private/unmarshaller.py | 517 +++++++++++++++-------------- dbus_next/constants.py | 4 + dbus_next/message.py | 26 +- dbus_next/signature.py | 78 ++--- dbus_next/validators.py | 6 +- test/test_marshaller.py | 25 +- 8 files changed, 367 insertions(+), 316 deletions(-) create mode 100644 bench/unmarshall.py diff --git a/bench/unmarshall.py b/bench/unmarshall.py new file mode 100644 index 0000000..cde28b3 --- /dev/null +++ b/bench/unmarshall.py @@ -0,0 +1,22 @@ +import io +import timeit + +from dbus_next._private.unmarshaller import Unmarshaller + +bluez_rssi_message = ( + "6c04010134000000e25389019500000001016f00250000002f6f72672f626c75657a2f686369302f6465" + "765f30385f33415f46325f31455f32425f3631000000020173001f0000006f72672e667265656465736b" + "746f702e444275732e50726f7065727469657300030173001100000050726f706572746965734368616e" + "67656400000000000000080167000873617b73767d617300000007017300040000003a312e3400000000" + "110000006f72672e626c75657a2e446576696365310000000e0000000000000004000000525353490001" + "6e00a7ff000000000000" +) + + +def unmarhsall_bluez_rssi_message(): + Unmarshaller(io.BytesIO(bytes.fromhex(bluez_rssi_message))).unmarshall() + + +count = 1000000 +time = timeit.Timer(unmarhsall_bluez_rssi_message).timeit(count) +print(f"Unmarshalling {count} bluetooth rssi messages took {time} seconds") diff --git a/dbus_next/_private/constants.py b/dbus_next/_private/constants.py index 22a6b80..3e4c813 100644 --- a/dbus_next/_private/constants.py +++ b/dbus_next/_private/constants.py @@ -16,3 +16,8 @@ class HeaderField(Enum): SENDER = 7 SIGNATURE = 8 UNIX_FDS = 9 + + +HEADER_NAME_MAP = { + field.value: field.name for field in HeaderField +} diff --git a/dbus_next/_private/unmarshaller.py b/dbus_next/_private/unmarshaller.py index 38ef657..814115e 100644 --- a/dbus_next/_private/unmarshaller.py +++ b/dbus_next/_private/unmarshaller.py @@ -1,307 +1,324 @@ +from typing import Any, Callable, Dict, List, Optional, Tuple from ..message import Message -from .constants import HeaderField, LITTLE_ENDIAN, BIG_ENDIAN, PROTOCOL_VERSION -from ..constants import MessageType, MessageFlag -from ..signature import SignatureTree, Variant +from .constants import ( + HeaderField, + LITTLE_ENDIAN, + BIG_ENDIAN, + PROTOCOL_VERSION, + HEADER_NAME_MAP, +) +from ..constants import MessageType, MessageFlag, MESSAGE_FLAG_MAP, MESSAGE_TYPE_MAP +from ..signature import SignatureTree, SignatureType, Variant from ..errors import InvalidMessageError import array +import contextlib +import io import socket -from codecs import decode -from struct import unpack_from +import sys +from struct import Struct MAX_UNIX_FDS = 16 +UNPACK_SYMBOL = {LITTLE_ENDIAN: "<", BIG_ENDIAN: ">"} +UNPACK_LENGTHS = {BIG_ENDIAN: Struct(">III"), LITTLE_ENDIAN: Struct(" bytes: + """reads from the socket, storing any fds sent and handling errors + from the read itself""" + unix_fd_list = array.array("i") - def read(self, n, prefetch=False): + try: + msg, ancdata, *_ = self.sock.recvmsg( + length, socket.CMSG_LEN(MAX_UNIX_FDS * unix_fd_list.itemsize) + ) + except BlockingIOError: + raise MarshallerStreamEndError() + + for level, type_, data in ancdata: + if not (level == socket.SOL_SOCKET and type_ == socket.SCM_RIGHTS): + continue + unix_fd_list.frombytes( + data[: len(data) - (len(data) % unix_fd_list.itemsize)] + ) + self.unix_fds.extend(list(unix_fd_list)) + + return msg + + def read(self, missing_bytes: int) -> None: """ Read from underlying socket into buffer and advance offset accordingly. :arg n: Number of bytes to read. If not enough bytes are available in the buffer, read more from it. - :arg prefetch: - Do not update current offset after reading. :returns: - Previous offset (before reading). To get the actual read bytes, - use the returned value and self.buf. + None """ - def read_sock(length): - '''reads from the socket, storing any fds sent and handling errors - from the read itself''' - if self.sock is not None: - unix_fd_list = array.array("i") - - try: - msg, ancdata, *_ = self.sock.recvmsg( - length, socket.CMSG_LEN(MAX_UNIX_FDS * unix_fd_list.itemsize)) - except BlockingIOError: - raise MarshallerStreamEndError() - - for level, type_, data in ancdata: - if not (level == socket.SOL_SOCKET and type_ == socket.SCM_RIGHTS): - continue - unix_fd_list.frombytes(data[:len(data) - (len(data) % unix_fd_list.itemsize)]) - self.unix_fds.extend(list(unix_fd_list)) - - return msg - else: - return self.stream.read(length) - - # store previously read data in a buffer so we can resume on socket - # interruptions - missing_bytes = n - (len(self.buf) - self.offset) - if missing_bytes > 0: - data = read_sock(missing_bytes) - if data == b'': - raise EOFError() - elif data is None: - raise MarshallerStreamEndError() - self.buf.extend(data) - if len(data) != missing_bytes: - raise MarshallerStreamEndError() - prev = self.offset - if not prefetch: - self.offset += n - return prev - - @staticmethod - def _padding(offset, align): - """ - Get padding bytes to get to the next align bytes mark. - - For any align value, the correct padding formula is: - - (align - (offset % align)) % align - - However, if align is a power of 2 (always the case here), the slow MOD - operator can be replaced by a bitwise AND: - - (align - (offset & (align - 1))) & (align - 1) - - Which can be simplified to: - - (-offset) & (align - 1) - """ - return (-offset) & (align - 1) - - def align(self, n): - padding = self._padding(self.offset, n) - if padding > 0: - self.read(padding) - - def read_byte(self, _=None): - return self.buf[self.read(1)] - - def read_boolean(self, _=None): - data = self.read_uint32() - if data: - return True + if self.sock is None: + data = self.stream.read(missing_bytes) else: - return False - - def read_int16(self, _=None): - return self.read_ctype('h', 2) - - def read_uint16(self, _=None): - return self.read_ctype('H', 2) - - def read_int32(self, _=None): - return self.read_ctype('i', 4) + data = self.read_sock(missing_bytes) + if data == b"": + raise EOFError() + if data is None: + raise MarshallerStreamEndError() + if len(data) != missing_bytes: + raise MarshallerStreamEndError() + self.buf.extend(data) - def read_uint32(self, _=None): - return self.read_ctype('I', 4) - - def read_int64(self, _=None): - return self.read_ctype('q', 8) - - def read_uint64(self, _=None): - return self.read_ctype('Q', 8) - - def read_double(self, _=None): - return self.read_ctype('d', 8) - - def read_ctype(self, fmt, size): - self.align(size) - if self.endian == LITTLE_ENDIAN: - fmt = '<' + fmt - else: - fmt = '>' + fmt - o = self.read(size) - return unpack_from(fmt, self.buf, o)[0] + def read_boolean(self, _=None): + return bool(self.read_argument(UINT32_SIGNATURE)) def read_string(self, _=None): - str_length = self.read_uint32() - o = self.read(str_length + 1) # read terminating '\0' byte as well - # avoid buffer copies when slicing - str_mem_slice = memoryview(self.buf)[o:o + str_length] - return decode(str_mem_slice) + str_length = self.read_argument(UINT32_SIGNATURE) + str_start = self.offset + # read terminating '\0' byte as well (str_length + 1) + self.offset += str_length + 1 + return self.buf[str_start : str_start + str_length].decode() def read_signature(self, _=None): - signature_len = self.read_byte() - o = self.read(signature_len + 1) # read terminating '\0' byte as well - # avoid buffer copies when slicing - sig_mem_slice = memoryview(self.buf)[o:o + signature_len] - return decode(sig_mem_slice) + signature_len = self.view[self.offset] # byte + o = self.offset + 1 + # read terminating '\0' byte as well (str_length + 1) + self.offset = o + signature_len + 1 + return self.buf[o : o + signature_len].decode() def read_variant(self, _=None): - signature = self.read_signature() - signature_tree = SignatureTree._get(signature) - value = self.read_argument(signature_tree.types[0]) - return Variant(signature_tree, value) + tree = SignatureTree._get(self.read_signature()) + # verify in Variant is only useful on construction not unmarshalling + return Variant(tree, self.read_argument(tree.types[0]), verify=False) - def read_struct(self, type_): - self.align(8) + def read_struct(self, type_: SignatureType): + self.offset += -self.offset & 7 # align 8 + return [self.read_argument(child_type) for child_type in type_.children] - result = [] - for child_type in type_.children: - result.append(self.read_argument(child_type)) + def read_dict_entry(self, type_: SignatureType): + self.offset += -self.offset & 7 # align 8 + return self.read_argument(type_.children[0]), self.read_argument( + type_.children[1] + ) - return result - - def read_dict_entry(self, type_): - self.align(8) - - key = self.read_argument(type_.children[0]) - value = self.read_argument(type_.children[1]) - - return key, value - - def read_array(self, type_): - self.align(4) - array_length = self.read_uint32() + def read_array(self, type_: SignatureType): + self.offset += -self.offset & 3 # align 4 for the array + array_length = self.read_argument(UINT32_SIGNATURE) child_type = type_.children[0] - if child_type.token in 'xtd{(': + if child_type.token in "xtd{(": # the first alignment is not included in the array size - self.align(8) + self.offset += -self.offset & 7 # align 8 + + if child_type.token == "y": + self.offset += array_length + return self.buf[self.offset - array_length : self.offset] beginning_offset = self.offset - result = None - if child_type.token == '{': - result = {} + if child_type.token == "{": + result_dict = {} while self.offset - beginning_offset < array_length: key, value = self.read_dict_entry(child_type) - result[key] = value - elif child_type.token == 'y': - o = self.read(array_length) - # avoid buffer copies when slicing - array_mem_slice = memoryview(self.buf)[o:o + array_length] - result = array_mem_slice.tobytes() - else: - result = [] - while self.offset - beginning_offset < array_length: - result.append(self.read_argument(child_type)) - - return result - - def read_argument(self, type_): - t = type_.token - - if t not in self.readers: - raise Exception(f'dont know how to read yet: "{t}"') - - return self.readers[t](type_) + result_dict[key] = value + return result_dict + + result_list = [] + while self.offset - beginning_offset < array_length: + result_list.append(self.read_argument(child_type)) + return result_list + + def read_argument(self, type_: SignatureType) -> Any: + """Dispatch to an argument reader or cast/unpack a C type.""" + token = type_.token + reader, ctype, size, struct = self.readers[token] + if reader: # complex type + return reader(self, type_) + self.offset += size + (-self.offset & (size - 1)) # align + if self.can_cast: + return self.view[self.offset - size : self.offset].cast(ctype)[0] + return struct.unpack_from(self.view, self.offset - size)[0] + + def header_fields(self, header_length): + """Header fields are always a(yv).""" + beginning_offset = self.offset + headers = {} + while self.offset - beginning_offset < header_length: + # Now read the y (byte) of struct (yv) + self.offset += (-self.offset & 7) + 1 # align 8 + 1 for 'y' byte + field_0 = self.view[self.offset - 1] + + # Now read the v (variant) of struct (yv) + signature_len = self.view[self.offset] # byte + o = self.offset + 1 + self.offset += signature_len + 2 # one for the byte, one for the '\0' + tree = SignatureTree._get(self.buf[o : o + signature_len].decode()) + headers[HEADER_NAME_MAP[field_0]] = self.read_argument(tree.types[0]) + return headers def _unmarshall(self): - self.offset = 0 - self.read(16, prefetch=True) - self.endian = self.read_byte() - if self.endian != LITTLE_ENDIAN and self.endian != BIG_ENDIAN: - raise InvalidMessageError('Expecting endianness as the first byte') - message_type = MessageType(self.read_byte()) - flags = MessageFlag(self.read_byte()) - - protocol_version = self.read_byte() - + # Signature is of the header is + # BYTE, BYTE, BYTE, BYTE, UINT32, UINT32, ARRAY of STRUCT of (BYTE,VARIANT) + self.read(HEADER_SIGNATURE_SIZE) + buffer = self.buf + endian = buffer[0] + message_type = buffer[1] + flags = buffer[2] + protocol_version = buffer[3] + + if endian != LITTLE_ENDIAN and endian != BIG_ENDIAN: + raise InvalidMessageError( + f"Expecting endianness as the first byte, got {endian} from {buffer}" + ) if protocol_version != PROTOCOL_VERSION: - raise InvalidMessageError(f'got unknown protocol version: {protocol_version}') - - body_len = self.read_uint32() - serial = self.read_uint32() - - header_len = self.read_uint32() - msg_len = header_len + self._padding(header_len, 8) + body_len - self.read(msg_len, prefetch=True) - # backtrack offset since header array length needs to be read again - self.offset -= 4 - - header_fields = {} - for field_struct in self.read_argument(SignatureTree._get('a(yv)').types[0]): - field = HeaderField(field_struct[0]) - header_fields[field.name] = field_struct[1].value - - self.align(8) - - path = header_fields.get(HeaderField.PATH.name) - interface = header_fields.get(HeaderField.INTERFACE.name) - member = header_fields.get(HeaderField.MEMBER.name) - error_name = header_fields.get(HeaderField.ERROR_NAME.name) - reply_serial = header_fields.get(HeaderField.REPLY_SERIAL.name) - destination = header_fields.get(HeaderField.DESTINATION.name) - sender = header_fields.get(HeaderField.SENDER.name) - signature = header_fields.get(HeaderField.SIGNATURE.name, '') - signature_tree = SignatureTree._get(signature) - # unix_fds = header_fields.get(HeaderField.UNIX_FDS.name, 0) - - body = [] + raise InvalidMessageError( + f"got unknown protocol version: {protocol_version}" + ) + + body_len, serial, header_len = UNPACK_LENGTHS[endian].unpack_from(buffer, 4) + msg_len = header_len + (-header_len & 7) + body_len # align 8 + if (sys.byteorder == "little" and endian == LITTLE_ENDIAN) or ( + sys.byteorder == "big" and endian == BIG_ENDIAN + ): + self.can_cast = True + self.readers = self._readers_by_type[endian] + self.read(msg_len) + self.view = memoryview(self.buf) + + self.offset = HEADER_ARRAY_OF_STRUCT_SIGNATURE_POSITION + header_fields = self.header_fields(header_len) + self.offset += -self.offset & 7 # align 8 + + tree = SignatureTree._get(header_fields.get(HeaderField.SIGNATURE.name, "")) if body_len: - for type_ in signature_tree.types: - body.append(self.read_argument(type_)) - - self.message = Message(destination=destination, - path=path, - interface=interface, - member=member, - message_type=message_type, - flags=flags, - error_name=error_name, - reply_serial=reply_serial, - sender=sender, - unix_fds=self.unix_fds, - signature=signature_tree, - body=body, - serial=serial) + body = [self.read_argument(type_) for type_ in tree.types] + else: + body = [] + + self.message = Message( + destination=header_fields.get(HEADER_DESTINATION), + path=header_fields.get(HEADER_PATH), + interface=header_fields.get(HEADER_INTERFACE), + member=header_fields.get(HEADER_MEMBER), + message_type=MESSAGE_TYPE_MAP[message_type], + flags=MESSAGE_FLAG_MAP[flags], + error_name=header_fields.get(HEADER_ERROR_NAME), + reply_serial=header_fields.get(HEADER_REPLY_SERIAL), + sender=header_fields.get(HEADER_SENDER), + unix_fds=self.unix_fds, + signature=tree.signature, + body=body, + serial=serial, + ) def unmarshall(self): - try: + with contextlib.suppress(MarshallerStreamEndError): self._unmarshall() return self.message - except MarshallerStreamEndError: - return None + return None + + _complex_parsers: Dict[ + str, Tuple[Callable[["Unmarshaller", SignatureType], Any], None, None, None] + ] = { + "b": (read_boolean, None, None, None), + "o": (read_string, None, None, None), + "s": (read_string, None, None, None), + "g": (read_signature, None, None, None), + "a": (read_array, None, None, None), + "(": (read_struct, None, None, None), + "{": (read_dict_entry, None, None, None), + "v": (read_variant, None, None, None), + } + + _ctype_by_endian: Dict[int, Dict[str, Tuple[None, str, int, Struct]]] = { + endian: { + dbus_type: ( + None, + *ctype_size, + Struct(f"{UNPACK_SYMBOL[endian]}{ctype_size[0]}"), + ) + for dbus_type, ctype_size in DBUS_TO_CTYPE.items() + } + for endian in (BIG_ENDIAN, LITTLE_ENDIAN) + } + + _readers_by_type: Dict[int, READER_TYPE] = { + BIG_ENDIAN: {**_ctype_by_endian[BIG_ENDIAN], **_complex_parsers}, + LITTLE_ENDIAN: {**_ctype_by_endian[LITTLE_ENDIAN], **_complex_parsers}, + } diff --git a/dbus_next/constants.py b/dbus_next/constants.py index 6afc9b8..5617462 100644 --- a/dbus_next/constants.py +++ b/dbus_next/constants.py @@ -17,6 +17,8 @@ class MessageType(Enum): SIGNAL = 4 #: A broadcast signal to subscribed connections +MESSAGE_TYPE_MAP = {field.value: field for field in MessageType} + class MessageFlag(IntFlag): """Flags that affect the behavior of sent and received messages """ @@ -26,6 +28,8 @@ class MessageFlag(IntFlag): ALLOW_INTERACTIVE_AUTHORIZATION = 4 +MESSAGE_FLAG_MAP = {field.value: field for field in MessageFlag} + class NameFlag(IntFlag): """A flag that affects the behavior of a name request. """ diff --git a/dbus_next/message.py b/dbus_next/message.py index 1f8085b..44a55b6 100644 --- a/dbus_next/message.py +++ b/dbus_next/message.py @@ -7,7 +7,12 @@ from typing import List, Any - +REQUIRED_FIELDS = { + MessageType.METHOD_CALL: ('path', 'member'), + MessageType.SIGNAL: ('path', 'member', 'interface'), + MessageType.ERROR: ('error_name', 'reply_serial'), + MessageType.METHOD_RETURN: ('reply_serial',), +} class Message: """A class for sending and receiving messages through the :class:`MessageBus ` with the @@ -95,21 +100,12 @@ def __init__(self, if self.error_name is not None: assert_interface_name_valid(self.error_name) - def require_fields(*fields): - for field in fields: - if not getattr(self, field): - raise InvalidMessageError(f'missing required field: {field}') - - if self.message_type == MessageType.METHOD_CALL: - require_fields('path', 'member') - elif self.message_type == MessageType.SIGNAL: - require_fields('path', 'member', 'interface') - elif self.message_type == MessageType.ERROR: - require_fields('error_name', 'reply_serial') - elif self.message_type == MessageType.METHOD_RETURN: - require_fields('reply_serial') - else: + required_fields = REQUIRED_FIELDS.get(self.message_type) + if not required_fields: raise InvalidMessageError(f'got unknown message type: {self.message_type}') + for field in required_fields: + if not getattr(self, field): + raise InvalidMessageError(f'missing required field: {field}') @staticmethod def new_error(msg: 'Message', error_name: str, error_text: str) -> 'Message': diff --git a/dbus_next/signature.py b/dbus_next/signature.py index 254c842..47aadd6 100644 --- a/dbus_next/signature.py +++ b/dbus_next/signature.py @@ -1,9 +1,11 @@ from .validators import is_object_path_valid from .errors import InvalidSignatureError, SignatureBodyMismatchError +from functools import lru_cache from typing import Any, List, Union + class SignatureType: """A class that represents a single complete type within a signature. @@ -20,9 +22,9 @@ class to parse signatures. """ _tokens = 'ybnqiuxtdsogavh({' - def __init__(self, token): + def __init__(self, token: str) -> None: self.token = token - self.children = [] + self.children: List[SignatureType] = [] self._signature = None def __eq__(self, other): @@ -257,43 +259,32 @@ def verify(self, body: Any) -> bool: """ if body is None: raise SignatureBodyMismatchError('Cannot serialize Python type "None"') - elif self.token == 'y': - self._verify_byte(body) - elif self.token == 'b': - self._verify_boolean(body) - elif self.token == 'n': - self._verify_int16(body) - elif self.token == 'q': - self._verify_uint16(body) - elif self.token == 'i': - self._verify_int32(body) - elif self.token == 'u': - self._verify_uint32(body) - elif self.token == 'x': - self._verify_int64(body) - elif self.token == 't': - self._verify_uint64(body) - elif self.token == 'd': - self._verify_double(body) - elif self.token == 'h': - self._verify_unix_fd(body) - elif self.token == 'o': - self._verify_object_path(body) - elif self.token == 's': - self._verify_string(body) - elif self.token == 'g': - self._verify_signature(body) - elif self.token == 'a': - self._verify_array(body) - elif self.token == '(': - self._verify_struct(body) - elif self.token == 'v': - self._verify_variant(body) + validator = self.validators.get(self.token) + if validator: + validator(self, body) else: raise Exception(f'cannot verify type with token {self.token}') return True + validators = { + "y": _verify_byte, + "b": _verify_boolean, + "n": _verify_int16, + "q": _verify_uint16, + "i": _verify_int32, + "u": _verify_uint32, + "x": _verify_int64, + "t": _verify_uint64, + "d": _verify_double, + "h": _verify_uint32, + "o": _verify_string, + "s": _verify_string, + "g": _verify_signature, + "a": _verify_array, + "(": _verify_struct, + "v": _verify_variant, + } class SignatureTree: """A class that represents a signature as a tree structure for conveniently @@ -311,19 +302,15 @@ class SignatureTree: :class:`InvalidSignatureError` if the given signature is not valid. """ - _cache = {} - @staticmethod - def _get(signature: str = ''): - if signature in SignatureTree._cache: - return SignatureTree._cache[signature] - SignatureTree._cache[signature] = SignatureTree(signature) - return SignatureTree._cache[signature] + @lru_cache(maxsize=None) + def _get(signature: str = '') -> "SignatureTree": + return SignatureTree(signature) def __init__(self, signature: str = ''): self.signature = signature - self.types = [] + self.types: List[SignatureType] = [] if len(signature) > 0xff: raise InvalidSignatureError('A signature must be less than 256 characters') @@ -381,7 +368,7 @@ class Variant: :class:`InvalidSignatureError` if the signature is not valid. :class:`SignatureBodyMismatchError` if the signature does not match the body. """ - def __init__(self, signature: Union[str, SignatureTree, SignatureType], value: Any): + def __init__(self, signature: Union[str, SignatureTree, SignatureType], value: Any, verify: bool = True): signature_str = '' signature_tree = None signature_type = None @@ -397,12 +384,13 @@ def __init__(self, signature: Union[str, SignatureTree, SignatureType], value: A raise TypeError('signature must be a SignatureTree, SignatureType, or a string') if signature_tree: - if len(signature_tree.types) != 1: + if verify and len(signature_tree.types) != 1: raise ValueError('variants must have a signature for a single complete type') signature_str = signature_tree.signature signature_type = signature_tree.types[0] - signature_type.verify(value) + if verify: + signature_type.verify(value) self.type = signature_type self.signature = signature_str diff --git a/dbus_next/validators.py b/dbus_next/validators.py index 3b73127..7216c5a 100644 --- a/dbus_next/validators.py +++ b/dbus_next/validators.py @@ -1,5 +1,6 @@ import re from .errors import InvalidBusNameError, InvalidObjectPathError, InvalidInterfaceNameError, InvalidMemberNameError +from functools import lru_cache _bus_name_re = re.compile(r'^[A-Za-z_-][A-Za-z0-9_-]*$') _path_re = re.compile(r'^[A-Za-z0-9_]+$') @@ -7,6 +8,7 @@ _member_re = re.compile(r'^[A-Za-z_][A-Za-z0-9_-]*$') +@lru_cache(maxsize=32) def is_bus_name_valid(name: str) -> bool: """Whether this is a valid bus name. @@ -41,6 +43,7 @@ def is_bus_name_valid(name: str) -> bool: return True +@lru_cache(maxsize=512) def is_object_path_valid(path: str) -> bool: """Whether this is a valid object path. @@ -71,6 +74,7 @@ def is_object_path_valid(path: str) -> bool: return True +@lru_cache(maxsize=32) def is_interface_name_valid(name: str) -> bool: """Whether this is a valid interface name. @@ -100,7 +104,7 @@ def is_interface_name_valid(name: str) -> bool: return True - +@lru_cache(maxsize=512) def is_member_name_valid(member: str) -> bool: """Whether this is a valid member name. diff --git a/test/test_marshaller.py b/test/test_marshaller.py index 65f6384..caad2ac 100644 --- a/test/test_marshaller.py +++ b/test/test_marshaller.py @@ -1,10 +1,13 @@ +from typing import Any from dbus_next._private.unmarshaller import Unmarshaller -from dbus_next import Message, Variant, SignatureTree +from dbus_next import Message, Variant, SignatureTree, MessageType, MessageFlag import json import os import io +import pytest + def print_buf(buf): i = 0 @@ -19,6 +22,17 @@ def print_buf(buf): # these messages have been verified with another library table = json.load(open(os.path.dirname(__file__) + '/data/messages.json')) +# these have unix_fds so we only test with unmarshalling +bluez_table = json.load(open(os.path.dirname(__file__) + '/data/bluez_messages.json')) + +def json_to_message(message: dict[str, Any]) -> Message: + copy = dict(message) + if "message_type" in copy: + copy['message_type'] = MessageType(copy['message_type']) + if "flags" in copy: + copy['flags'] = MessageFlag(copy['flags']) + + return Message(**copy) # variants are an object in the json def replace_variants(type_, item): @@ -54,7 +68,7 @@ def dumper(obj): def test_marshalling_with_table(): for item in table: - message = Message(**item['message']) + message = json_to_message(item['message']) body = [] for i, type_ in enumerate(message.signature_tree.types): @@ -77,8 +91,9 @@ def test_marshalling_with_table(): assert buf == data -def test_unmarshalling_with_table(): - for item in table: +@pytest.mark.parametrize('unmarshall_table', (table, bluez_table)) +def test_unmarshalling_with_table(unmarshall_table): + for item in unmarshall_table: stream = io.BytesIO(bytes.fromhex(item['data'])) unmarshaller = Unmarshaller(stream) @@ -89,7 +104,7 @@ def test_unmarshalling_with_table(): print(json_dump(item['message'])) raise e - message = Message(**item['message']) + message = json_to_message(item['message']) body = [] for i, type_ in enumerate(message.signature_tree.types): From bab7e9a231a1f442a654b4b68123636e36147594 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 6 Aug 2022 10:27:23 -1000 Subject: [PATCH 02/17] blow up on end of message so we raise higher in the stack --- dbus_next/_private/unmarshaller.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dbus_next/_private/unmarshaller.py b/dbus_next/_private/unmarshaller.py index 814115e..63e9077 100644 --- a/dbus_next/_private/unmarshaller.py +++ b/dbus_next/_private/unmarshaller.py @@ -288,10 +288,8 @@ def _unmarshall(self): ) def unmarshall(self): - with contextlib.suppress(MarshallerStreamEndError): - self._unmarshall() - return self.message - return None + self._unmarshall() + return self.message _complex_parsers: Dict[ str, Tuple[Callable[["Unmarshaller", SignatureType], Any], None, None, None] From efe1dc0fb0b116c618cb6cf81f5ffb462cb21ac0 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 6 Aug 2022 10:42:57 -1000 Subject: [PATCH 03/17] fix resume --- dbus_next/_private/unmarshaller.py | 46 +++++++++++++++++++----------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/dbus_next/_private/unmarshaller.py b/dbus_next/_private/unmarshaller.py index 63e9077..4640954 100644 --- a/dbus_next/_private/unmarshaller.py +++ b/dbus_next/_private/unmarshaller.py @@ -98,6 +98,11 @@ def __init__(self, stream: io.BufferedRWPair, sock=None): self.sock = sock self.message = None self.readers = None + self.body_len: int | None = None + self.serial: int | None = None + self.header_len: int | None = None + self.message_type: MessageType | None = None + self.flag: MessageFlag | None = None def read_sock(self, length: int) -> bytes: """reads from the socket, storing any fds sent and handling errors @@ -121,17 +126,18 @@ def read_sock(self, length: int) -> bytes: return msg - def read(self, missing_bytes: int) -> None: + def read(self, to_offset: int) -> None: """ - Read from underlying socket into buffer and advance offset accordingly. + Read from underlying socket into buffer. - :arg n: - Number of bytes to read. If not enough bytes are available in the + :arg to_offset: + The offset to read to. If not enough bytes are available in the buffer, read more from it. :returns: None """ + missing_bytes = to_offset - (len(self.buf) - self.offset) if self.sock is None: data = self.stream.read(missing_bytes) else: @@ -231,14 +237,15 @@ def header_fields(self, header_length): headers[HEADER_NAME_MAP[field_0]] = self.read_argument(tree.types[0]) return headers - def _unmarshall(self): + def _read_header(self): + """Read the header of the message.""" # Signature is of the header is # BYTE, BYTE, BYTE, BYTE, UINT32, UINT32, ARRAY of STRUCT of (BYTE,VARIANT) self.read(HEADER_SIGNATURE_SIZE) buffer = self.buf endian = buffer[0] - message_type = buffer[1] - flags = buffer[2] + self.message_type = MESSAGE_TYPE_MAP[buffer[1]] + self.flag = MESSAGE_FLAG_MAP[buffer[2]] protocol_version = buffer[3] if endian != LITTLE_ENDIAN and endian != BIG_ENDIAN: @@ -250,23 +257,26 @@ def _unmarshall(self): f"got unknown protocol version: {protocol_version}" ) - body_len, serial, header_len = UNPACK_LENGTHS[endian].unpack_from(buffer, 4) - msg_len = header_len + (-header_len & 7) + body_len # align 8 + self.body_len, self.serial, self.header_len = UNPACK_LENGTHS[endian].unpack_from(buffer, 4) + self.msg_len = self.header_len + (-self.header_len & 7) + self.body_len # align 8 if (sys.byteorder == "little" and endian == LITTLE_ENDIAN) or ( sys.byteorder == "big" and endian == BIG_ENDIAN ): self.can_cast = True self.readers = self._readers_by_type[endian] - self.read(msg_len) + + def _read_body(self): + """Read the body of the message.""" + self.read(self.msg_len) self.view = memoryview(self.buf) self.offset = HEADER_ARRAY_OF_STRUCT_SIGNATURE_POSITION - header_fields = self.header_fields(header_len) + header_fields = self.header_fields(self.header_len) self.offset += -self.offset & 7 # align 8 tree = SignatureTree._get(header_fields.get(HeaderField.SIGNATURE.name, "")) - if body_len: + if self.body_len: body = [self.read_argument(type_) for type_ in tree.types] else: body = [] @@ -276,19 +286,23 @@ def _unmarshall(self): path=header_fields.get(HEADER_PATH), interface=header_fields.get(HEADER_INTERFACE), member=header_fields.get(HEADER_MEMBER), - message_type=MESSAGE_TYPE_MAP[message_type], - flags=MESSAGE_FLAG_MAP[flags], + message_type=self.message_type, + flags=self.flag, error_name=header_fields.get(HEADER_ERROR_NAME), reply_serial=header_fields.get(HEADER_REPLY_SERIAL), sender=header_fields.get(HEADER_SENDER), unix_fds=self.unix_fds, signature=tree.signature, body=body, - serial=serial, + serial=self.serial, ) def unmarshall(self): - self._unmarshall() + """Unmarshall the message.""" + with contextlib.suppress(MarshallerStreamEndError): + if not self.message_type: + self._read_header() + self._read_body() return self.message _complex_parsers: Dict[ From a75c95b8da74a3a81b2ed64a08f8392569e0f2f0 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 6 Aug 2022 10:53:36 -1000 Subject: [PATCH 04/17] fix resume --- dbus_next/_private/unmarshaller.py | 44 ++++++++++++++++-------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/dbus_next/_private/unmarshaller.py b/dbus_next/_private/unmarshaller.py index 4640954..6d415ae 100644 --- a/dbus_next/_private/unmarshaller.py +++ b/dbus_next/_private/unmarshaller.py @@ -12,7 +12,6 @@ from ..errors import InvalidMessageError import array -import contextlib import io import socket import sys @@ -126,18 +125,20 @@ def read_sock(self, length: int) -> bytes: return msg - def read(self, to_offset: int) -> None: + def read_to_offset(self, offset: int) -> None: """ Read from underlying socket into buffer. - :arg to_offset: + Raises MarshallerStreamEndError if there is not enough data to be read. + + :arg offset: The offset to read to. If not enough bytes are available in the buffer, read more from it. :returns: None """ - missing_bytes = to_offset - (len(self.buf) - self.offset) + missing_bytes = offset - (len(self.buf) - self.offset) if self.sock is None: data = self.stream.read(missing_bytes) else: @@ -146,9 +147,9 @@ def read(self, to_offset: int) -> None: raise EOFError() if data is None: raise MarshallerStreamEndError() + self.buf.extend(data) if len(data) != missing_bytes: raise MarshallerStreamEndError() - self.buf.extend(data) def read_boolean(self, _=None): return bool(self.read_argument(UINT32_SIGNATURE)) @@ -241,7 +242,7 @@ def _read_header(self): """Read the header of the message.""" # Signature is of the header is # BYTE, BYTE, BYTE, BYTE, UINT32, UINT32, ARRAY of STRUCT of (BYTE,VARIANT) - self.read(HEADER_SIGNATURE_SIZE) + self.read_to_offset(HEADER_SIGNATURE_SIZE) buffer = self.buf endian = buffer[0] self.message_type = MESSAGE_TYPE_MAP[buffer[1]] @@ -257,8 +258,12 @@ def _read_header(self): f"got unknown protocol version: {protocol_version}" ) - self.body_len, self.serial, self.header_len = UNPACK_LENGTHS[endian].unpack_from(buffer, 4) - self.msg_len = self.header_len + (-self.header_len & 7) + self.body_len # align 8 + self.body_len, self.serial, self.header_len = UNPACK_LENGTHS[ + endian + ].unpack_from(buffer, 4) + self.msg_len = ( + self.header_len + (-self.header_len & 7) + self.body_len + ) # align 8 if (sys.byteorder == "little" and endian == LITTLE_ENDIAN) or ( sys.byteorder == "big" and endian == BIG_ENDIAN ): @@ -267,20 +272,12 @@ def _read_header(self): def _read_body(self): """Read the body of the message.""" - self.read(self.msg_len) + self.read_to_offset(HEADER_SIGNATURE_SIZE + self.msg_len) self.view = memoryview(self.buf) - self.offset = HEADER_ARRAY_OF_STRUCT_SIGNATURE_POSITION header_fields = self.header_fields(self.header_len) self.offset += -self.offset & 7 # align 8 - tree = SignatureTree._get(header_fields.get(HeaderField.SIGNATURE.name, "")) - - if self.body_len: - body = [self.read_argument(type_) for type_ in tree.types] - else: - body = [] - self.message = Message( destination=header_fields.get(HEADER_DESTINATION), path=header_fields.get(HEADER_PATH), @@ -293,16 +290,23 @@ def _read_body(self): sender=header_fields.get(HEADER_SENDER), unix_fds=self.unix_fds, signature=tree.signature, - body=body, + body=[self.read_argument(t) for t in tree.types] if self.body_len else [], serial=self.serial, ) def unmarshall(self): - """Unmarshall the message.""" - with contextlib.suppress(MarshallerStreamEndError): + """Unmarshall the message. + + The underlying read function will raise MarshallerStreamEndError + if there are not enough bytes in the buffer. This allows unmarshall + to be resumed when more data comes in over the wire. + """ + try: if not self.message_type: self._read_header() self._read_body() + except MarshallerStreamEndError: + return None return self.message _complex_parsers: Dict[ From 8cd497051506be42c0b64a2c4d0fc7f024abf327 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 6 Aug 2022 11:01:34 -1000 Subject: [PATCH 05/17] add resume test --- test/test_marshaller.py | 103 ++++++++++++++++++++++++++++------------ 1 file changed, 73 insertions(+), 30 deletions(-) diff --git a/test/test_marshaller.py b/test/test_marshaller.py index caad2ac..53347d7 100644 --- a/test/test_marshaller.py +++ b/test/test_marshaller.py @@ -12,7 +12,7 @@ def print_buf(buf): i = 0 while True: - p = buf[i:i + 8] + p = buf[i : i + 8] if not p: break print(p) @@ -20,35 +20,39 @@ def print_buf(buf): # these messages have been verified with another library -table = json.load(open(os.path.dirname(__file__) + '/data/messages.json')) +table = json.load(open(os.path.dirname(__file__) + "/data/messages.json")) # these have unix_fds so we only test with unmarshalling -bluez_table = json.load(open(os.path.dirname(__file__) + '/data/bluez_messages.json')) +bluez_table = json.load(open(os.path.dirname(__file__) + "/data/bluez_messages.json")) + def json_to_message(message: dict[str, Any]) -> Message: copy = dict(message) if "message_type" in copy: - copy['message_type'] = MessageType(copy['message_type']) + copy["message_type"] = MessageType(copy["message_type"]) if "flags" in copy: - copy['flags'] = MessageFlag(copy['flags']) + copy["flags"] = MessageFlag(copy["flags"]) return Message(**copy) + # variants are an object in the json def replace_variants(type_, item): - if type_.token == 'v' and type(item) is not Variant: - item = Variant(item['signature'], - replace_variants(SignatureTree(item['signature']).types[0], item['value'])) - elif type_.token == 'a': + if type_.token == "v" and type(item) is not Variant: + item = Variant( + item["signature"], + replace_variants(SignatureTree(item["signature"]).types[0], item["value"]), + ) + elif type_.token == "a": for i, item_child in enumerate(item): - if type_.children[0].token == '{': + if type_.children[0].token == "{": for k, v in item.items(): item[k] = replace_variants(type_.children[0].children[1], v) else: item[i] = replace_variants(type_.children[0], item_child) - elif type_.token == '(': + elif type_.token == "(": for i, item_child in enumerate(item): - if type_.children[0].token == '{': + if type_.children[0].token == "{": assert False else: item[i] = replace_variants(type_.children[i], item_child) @@ -68,7 +72,7 @@ def dumper(obj): def test_marshalling_with_table(): for item in table: - message = json_to_message(item['message']) + message = json_to_message(item["message"]) body = [] for i, type_ in enumerate(message.signature_tree.types): @@ -76,35 +80,35 @@ def test_marshalling_with_table(): message.body = body buf = message._marshall() - data = bytes.fromhex(item['data']) + data = bytes.fromhex(item["data"]) if buf != data: - print('message:') - print(json_dump(item['message'])) - print('') - print('mine:') + print("message:") + print(json_dump(item["message"])) + print("") + print("mine:") print_buf(bytes(buf)) - print('') - print('theirs:') + print("") + print("theirs:") print_buf(data) assert buf == data -@pytest.mark.parametrize('unmarshall_table', (table, bluez_table)) +@pytest.mark.parametrize("unmarshall_table", (table, bluez_table)) def test_unmarshalling_with_table(unmarshall_table): for item in unmarshall_table: - stream = io.BytesIO(bytes.fromhex(item['data'])) + stream = io.BytesIO(bytes.fromhex(item["data"])) unmarshaller = Unmarshaller(stream) try: unmarshaller.unmarshall() except Exception as e: - print('message failed to unmarshall:') - print(json_dump(item['message'])) + print("message failed to unmarshall:") + print(json_dump(item["message"])) raise e - message = json_to_message(item['message']) + message = json_to_message(item["message"]) body = [] for i, type_ in enumerate(message.signature_tree.types): @@ -112,16 +116,55 @@ def test_unmarshalling_with_table(unmarshall_table): message.body = body for attr in [ - 'body', 'signature', 'message_type', 'destination', 'path', 'interface', 'member', - 'flags', 'serial' + "body", + "signature", + "message_type", + "destination", + "path", + "interface", + "member", + "flags", + "serial", ]: - assert getattr(unmarshaller.message, - attr) == getattr(message, attr), f'attr doesnt match: {attr}' + assert getattr(unmarshaller.message, attr) == getattr( + message, attr + ), f"attr doesnt match: {attr}" + + +def test_unmarshall_can_resume(): + """Verify resume works.""" + bluez_rssi_message = ( + "6c04010134000000e25389019500000001016f00250000002f6f72672f626c75657a2f686369302f6465" + "765f30385f33415f46325f31455f32425f3631000000020173001f0000006f72672e667265656465736b" + "746f702e444275732e50726f7065727469657300030173001100000050726f706572746965734368616e" + "67656400000000000000080167000873617b73767d617300000007017300040000003a312e3400000000" + "110000006f72672e626c75657a2e446576696365310000000e0000000000000004000000525353490001" + "6e00a7ff000000000000" + ) + + class SlowStream(io.IOBase): + """A fake stream that will only give us one byte at a time.""" + + def __init__(self): + self.data = bytes.fromhex(bluez_rssi_message) + self.pos = 0 + + def read(self, n): + data = self.data[self.pos : self.pos + 1] + self.pos += 1 + return data + + stream = SlowStream() + unmarshaller = Unmarshaller(stream) + try: + unmarshaller.unmarshall() + except Exception as e: + raise e def test_ay_buffer(): body = [bytes(10000)] - msg = Message(path='/test', member='test', signature='ay', body=body) + msg = Message(path="/test", member="test", signature="ay", body=body) marshalled = msg._marshall() unmarshalled_msg = Unmarshaller(io.BytesIO(marshalled)).unmarshall() assert unmarshalled_msg.body[0] == body[0] From 4151555e72f568a473a726820c78b60ef702ba84 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 6 Aug 2022 11:12:50 -1000 Subject: [PATCH 06/17] fix test --- dbus_next/_private/unmarshaller.py | 5 +++-- test/test_marshaller.py | 14 ++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/dbus_next/_private/unmarshaller.py b/dbus_next/_private/unmarshaller.py index 6d415ae..0bbdd31 100644 --- a/dbus_next/_private/unmarshaller.py +++ b/dbus_next/_private/unmarshaller.py @@ -138,7 +138,8 @@ def read_to_offset(self, offset: int) -> None: :returns: None """ - missing_bytes = offset - (len(self.buf) - self.offset) + start_len = len(self.buf) + missing_bytes = offset - (start_len - self.offset) if self.sock is None: data = self.stream.read(missing_bytes) else: @@ -148,7 +149,7 @@ def read_to_offset(self, offset: int) -> None: if data is None: raise MarshallerStreamEndError() self.buf.extend(data) - if len(data) != missing_bytes: + if len(data) + start_len != offset: raise MarshallerStreamEndError() def read_boolean(self, _=None): diff --git a/test/test_marshaller.py b/test/test_marshaller.py index 53347d7..785bd74 100644 --- a/test/test_marshaller.py +++ b/test/test_marshaller.py @@ -141,25 +141,27 @@ def test_unmarshall_can_resume(): "110000006f72672e626c75657a2e446576696365310000000e0000000000000004000000525353490001" "6e00a7ff000000000000" ) + message_bytes = bytes.fromhex(bluez_rssi_message) class SlowStream(io.IOBase): """A fake stream that will only give us one byte at a time.""" def __init__(self): - self.data = bytes.fromhex(bluez_rssi_message) + self.data = message_bytes self.pos = 0 - def read(self, n): + def read(self, n) -> bytes: data = self.data[self.pos : self.pos + 1] self.pos += 1 return data stream = SlowStream() unmarshaller = Unmarshaller(stream) - try: - unmarshaller.unmarshall() - except Exception as e: - raise e + + for _ in range(len(bluez_rssi_message)): + if unmarshaller.unmarshall(): + break + assert unmarshaller.message is not None def test_ay_buffer(): From 276259f96403c697d59eda4d6aa5769dde7a935c Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 6 Aug 2022 11:20:13 -1000 Subject: [PATCH 07/17] docs --- dbus_next/_private/unmarshaller.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dbus_next/_private/unmarshaller.py b/dbus_next/_private/unmarshaller.py index 0bbdd31..5f67429 100644 --- a/dbus_next/_private/unmarshaller.py +++ b/dbus_next/_private/unmarshaller.py @@ -59,6 +59,13 @@ class MarshallerStreamEndError(Exception): + """This exception is raised when the end of the stream is reached. + + This means more data is expected on the wire that has not yet been + received. The caller should call unmarshall later when more data is + available. + """ + pass From 2b184b2168d204f1bae37cfa033587949fc74000 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 11 Sep 2022 12:11:01 -0500 Subject: [PATCH 08/17] strip moved tests --- test/test_marshaller.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/test_marshaller.py b/test/test_marshaller.py index 785bd74..b516e6d 100644 --- a/test/test_marshaller.py +++ b/test/test_marshaller.py @@ -22,8 +22,6 @@ def print_buf(buf): # these messages have been verified with another library table = json.load(open(os.path.dirname(__file__) + "/data/messages.json")) -# these have unix_fds so we only test with unmarshalling -bluez_table = json.load(open(os.path.dirname(__file__) + "/data/bluez_messages.json")) def json_to_message(message: dict[str, Any]) -> Message: @@ -95,7 +93,7 @@ def test_marshalling_with_table(): assert buf == data -@pytest.mark.parametrize("unmarshall_table", (table, bluez_table)) +@pytest.mark.parametrize("unmarshall_table", (table, )) def test_unmarshalling_with_table(unmarshall_table): for item in unmarshall_table: From c947b2b27c45287ae118568aa19a18f2e728a0ee Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 11 Sep 2022 12:11:49 -0500 Subject: [PATCH 09/17] fix for legacy typing --- test/test_marshaller.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_marshaller.py b/test/test_marshaller.py index b516e6d..11ab221 100644 --- a/test/test_marshaller.py +++ b/test/test_marshaller.py @@ -1,4 +1,4 @@ -from typing import Any +from typing import Any, Dict from dbus_next._private.unmarshaller import Unmarshaller from dbus_next import Message, Variant, SignatureTree, MessageType, MessageFlag @@ -24,7 +24,7 @@ def print_buf(buf): -def json_to_message(message: dict[str, Any]) -> Message: +def json_to_message(message: Dict[str, Any]) -> Message: copy = dict(message) if "message_type" in copy: copy["message_type"] = MessageType(copy["message_type"]) From ab86377e97b5613d6f61913b49c55a74333bac13 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 11 Sep 2022 12:12:36 -0500 Subject: [PATCH 10/17] loosen validator --- dbus_next/signature.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbus_next/signature.py b/dbus_next/signature.py index 47aadd6..3cf279a 100644 --- a/dbus_next/signature.py +++ b/dbus_next/signature.py @@ -218,7 +218,7 @@ def _verify_array(self, body): child_type.children[0].verify(key) child_type.children[1].verify(value) elif child_type.token == 'y': - if not isinstance(body, bytes): + if not isinstance(body, (bytearray, bytes)): raise SignatureBodyMismatchError( f'DBus ARRAY type "a" with BYTE child must be Python type "bytes", got {type(body)}' ) From 99643915ead713dc94fedd557edc2fd57c2063a3 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 11 Sep 2022 12:13:16 -0500 Subject: [PATCH 11/17] remove unreachable validators --- test/test_validators.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/test_validators.py b/test/test_validators.py index e0bfc7c..dd4dde9 100644 --- a/test/test_validators.py +++ b/test/test_validators.py @@ -5,7 +5,7 @@ def test_object_path_validator(): valid_paths = ['/', '/foo', '/foo/bar', '/foo/bar/bat'] invalid_paths = [ - None, {}, '', 'foo', 'foo/bar', '/foo/bar/', '/$/foo/bar', '/foo//bar', '/foo$bar/baz' + None, '', 'foo', 'foo/bar', '/foo/bar/', '/$/foo/bar', '/foo//bar', '/foo$bar/baz' ] for path in valid_paths: @@ -20,7 +20,7 @@ def test_bus_name_validator(): 'org.mpris.MediaPlayer2.google-play-desktop-player' ] invalid_names = [ - None, {}, '', '5foo.bar', 'foo.6bar', '.foo.bar', 'bar..baz', '$foo.bar', 'foo$.ba$r' + None, '', '5foo.bar', 'foo.6bar', '.foo.bar', 'bar..baz', '$foo.bar', 'foo$.ba$r' ] for name in valid_names: @@ -32,7 +32,7 @@ def test_bus_name_validator(): def test_interface_name_validator(): valid_names = ['foo.bar', 'foo.bar.bat', '_foo._bar', 'foo.bar69'] invalid_names = [ - None, {}, '', '5foo.bar', 'foo.6bar', '.foo.bar', 'bar..baz', '$foo.bar', 'foo$.ba$r', + None, '', '5foo.bar', 'foo.6bar', '.foo.bar', 'bar..baz', '$foo.bar', 'foo$.ba$r', 'org.mpris.MediaPlayer2.google-play-desktop-player' ] @@ -44,7 +44,7 @@ def test_interface_name_validator(): def test_member_name_validator(): valid_members = ['foo', 'FooBar', 'Bat_Baz69', 'foo-bar'] - invalid_members = [None, {}, '', 'foo.bar', '5foo', 'foo$bar'] + invalid_members = [None, '', 'foo.bar', '5foo', 'foo$bar'] for member in valid_members: assert is_member_name_valid(member), f'member name should be valid: "{member}"' From 59019653ca053d66b1b7040583ecd9c7d0c81dae Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 11 Sep 2022 12:14:59 -0500 Subject: [PATCH 12/17] Update dbus_next/validators.py --- dbus_next/validators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbus_next/validators.py b/dbus_next/validators.py index 7216c5a..2a93cab 100644 --- a/dbus_next/validators.py +++ b/dbus_next/validators.py @@ -43,7 +43,7 @@ def is_bus_name_valid(name: str) -> bool: return True -@lru_cache(maxsize=512) +@lru_cache(maxsize=1024) def is_object_path_valid(path: str) -> bool: """Whether this is a valid object path. From 044e462a45a3f61b9dd488b4c9d402955f928a72 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 11 Sep 2022 12:20:55 -0500 Subject: [PATCH 13/17] lint --- dbus_next/_private/unmarshaller.py | 10 +++++----- dbus_next/constants.py | 2 ++ dbus_next/message.py | 2 ++ dbus_next/signature.py | 2 +- dbus_next/validators.py | 1 + test/test_marshaller.py | 5 ++--- 6 files changed, 13 insertions(+), 9 deletions(-) diff --git a/dbus_next/_private/unmarshaller.py b/dbus_next/_private/unmarshaller.py index 5f67429..35dc776 100644 --- a/dbus_next/_private/unmarshaller.py +++ b/dbus_next/_private/unmarshaller.py @@ -167,14 +167,14 @@ def read_string(self, _=None): str_start = self.offset # read terminating '\0' byte as well (str_length + 1) self.offset += str_length + 1 - return self.buf[str_start : str_start + str_length].decode() + return self.buf[str_start:str_start + str_length].decode() def read_signature(self, _=None): signature_len = self.view[self.offset] # byte o = self.offset + 1 # read terminating '\0' byte as well (str_length + 1) self.offset = o + signature_len + 1 - return self.buf[o : o + signature_len].decode() + return self.buf[o:o + signature_len].decode() def read_variant(self, _=None): tree = SignatureTree._get(self.read_signature()) @@ -202,7 +202,7 @@ def read_array(self, type_: SignatureType): if child_type.token == "y": self.offset += array_length - return self.buf[self.offset - array_length : self.offset] + return self.buf[self.offset - array_length:self.offset] beginning_offset = self.offset @@ -226,7 +226,7 @@ def read_argument(self, type_: SignatureType) -> Any: return reader(self, type_) self.offset += size + (-self.offset & (size - 1)) # align if self.can_cast: - return self.view[self.offset - size : self.offset].cast(ctype)[0] + return self.view[self.offset - size:self.offset].cast(ctype)[0] return struct.unpack_from(self.view, self.offset - size)[0] def header_fields(self, header_length): @@ -242,7 +242,7 @@ def header_fields(self, header_length): signature_len = self.view[self.offset] # byte o = self.offset + 1 self.offset += signature_len + 2 # one for the byte, one for the '\0' - tree = SignatureTree._get(self.buf[o : o + signature_len].decode()) + tree = SignatureTree._get(self.buf[o:o + signature_len].decode()) headers[HEADER_NAME_MAP[field_0]] = self.read_argument(tree.types[0]) return headers diff --git a/dbus_next/constants.py b/dbus_next/constants.py index 5617462..b9494f8 100644 --- a/dbus_next/constants.py +++ b/dbus_next/constants.py @@ -19,6 +19,7 @@ class MessageType(Enum): MESSAGE_TYPE_MAP = {field.value: field for field in MessageType} + class MessageFlag(IntFlag): """Flags that affect the behavior of sent and received messages """ @@ -30,6 +31,7 @@ class MessageFlag(IntFlag): MESSAGE_FLAG_MAP = {field.value: field for field in MessageFlag} + class NameFlag(IntFlag): """A flag that affects the behavior of a name request. """ diff --git a/dbus_next/message.py b/dbus_next/message.py index 44a55b6..6685177 100644 --- a/dbus_next/message.py +++ b/dbus_next/message.py @@ -13,6 +13,8 @@ MessageType.ERROR: ('error_name', 'reply_serial'), MessageType.METHOD_RETURN: ('reply_serial',), } + + class Message: """A class for sending and receiving messages through the :class:`MessageBus ` with the diff --git a/dbus_next/signature.py b/dbus_next/signature.py index 3cf279a..2911efb 100644 --- a/dbus_next/signature.py +++ b/dbus_next/signature.py @@ -5,7 +5,6 @@ from typing import Any, List, Union - class SignatureType: """A class that represents a single complete type within a signature. @@ -286,6 +285,7 @@ def verify(self, body: Any) -> bool: "v": _verify_variant, } + class SignatureTree: """A class that represents a signature as a tree structure for conveniently working with DBus signatures. diff --git a/dbus_next/validators.py b/dbus_next/validators.py index 2a93cab..9460200 100644 --- a/dbus_next/validators.py +++ b/dbus_next/validators.py @@ -104,6 +104,7 @@ def is_interface_name_valid(name: str) -> bool: return True + @lru_cache(maxsize=512) def is_member_name_valid(member: str) -> bool: """Whether this is a valid member name. diff --git a/test/test_marshaller.py b/test/test_marshaller.py index 11ab221..b14e2b7 100644 --- a/test/test_marshaller.py +++ b/test/test_marshaller.py @@ -12,7 +12,7 @@ def print_buf(buf): i = 0 while True: - p = buf[i : i + 8] + p = buf[i:i + 8] if not p: break print(p) @@ -23,7 +23,6 @@ def print_buf(buf): table = json.load(open(os.path.dirname(__file__) + "/data/messages.json")) - def json_to_message(message: Dict[str, Any]) -> Message: copy = dict(message) if "message_type" in copy: @@ -149,7 +148,7 @@ def __init__(self): self.pos = 0 def read(self, n) -> bytes: - data = self.data[self.pos : self.pos + 1] + data = self.data[self.pos:self.pos + 1] self.pos += 1 return data From c2d61e2cf7e2cb9b86980f7f98568a8f1bd5c7c2 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 11 Sep 2022 12:25:12 -0500 Subject: [PATCH 14/17] reformat with yapf --- dbus_next/_private/constants.py | 4 +- dbus_next/_private/marshaller.py | 1 + dbus_next/_private/unmarshaller.py | 75 ++++++++++-------------- dbus_next/_private/util.py | 1 + dbus_next/aio/message_bus.py | 3 + dbus_next/aio/proxy_object.py | 4 ++ dbus_next/auth.py | 3 + dbus_next/errors.py | 5 ++ dbus_next/glib/message_bus.py | 5 ++ dbus_next/glib/proxy_object.py | 5 ++ dbus_next/introspection.py | 6 ++ dbus_next/message.py | 3 +- dbus_next/message_bus.py | 3 + dbus_next/proxy_object.py | 3 + dbus_next/service.py | 5 ++ dbus_next/signature.py | 6 +- examples/example-service.py | 1 + test/client/test_methods.py | 1 + test/client/test_properties.py | 1 + test/client/test_signals.py | 1 + test/service/test_decorators.py | 1 + test/service/test_export.py | 1 + test/service/test_methods.py | 2 + test/service/test_properties.py | 2 + test/service/test_signals.py | 3 + test/service/test_standard_interfaces.py | 2 + test/test_big_message.py | 1 + test/test_fd_passing.py | 1 + test/test_marshaller.py | 27 ++++----- 29 files changed, 112 insertions(+), 64 deletions(-) diff --git a/dbus_next/_private/constants.py b/dbus_next/_private/constants.py index 3e4c813..d9ee0c2 100644 --- a/dbus_next/_private/constants.py +++ b/dbus_next/_private/constants.py @@ -18,6 +18,4 @@ class HeaderField(Enum): UNIX_FDS = 9 -HEADER_NAME_MAP = { - field.value: field.name for field in HeaderField -} +HEADER_NAME_MAP = {field.value: field.name for field in HeaderField} diff --git a/dbus_next/_private/marshaller.py b/dbus_next/_private/marshaller.py index db71dee..706f430 100644 --- a/dbus_next/_private/marshaller.py +++ b/dbus_next/_private/marshaller.py @@ -3,6 +3,7 @@ class Marshaller: + def __init__(self, signature, body): self.signature_tree = SignatureTree._get(signature) self.signature_tree.verify(body) diff --git a/dbus_next/_private/unmarshaller.py b/dbus_next/_private/unmarshaller.py index 35dc776..8784088 100644 --- a/dbus_next/_private/unmarshaller.py +++ b/dbus_next/_private/unmarshaller.py @@ -47,15 +47,8 @@ HEADER_REPLY_SERIAL = HeaderField.REPLY_SERIAL.name HEADER_SENDER = HeaderField.SENDER.name -READER_TYPE = Dict[ - str, - Tuple[ - Optional[Callable[["Unmarshaller", SignatureType], Any]], - Optional[str], - Optional[int], - Optional[Struct], - ], -] +READER_TYPE = Dict[str, Tuple[Optional[Callable[["Unmarshaller", SignatureType], Any]], + Optional[str], Optional[int], Optional[Struct], ], ] class MarshallerStreamEndError(Exception): @@ -117,17 +110,14 @@ def read_sock(self, length: int) -> bytes: try: msg, ancdata, *_ = self.sock.recvmsg( - length, socket.CMSG_LEN(MAX_UNIX_FDS * unix_fd_list.itemsize) - ) + length, socket.CMSG_LEN(MAX_UNIX_FDS * unix_fd_list.itemsize)) except BlockingIOError: raise MarshallerStreamEndError() for level, type_, data in ancdata: if not (level == socket.SOL_SOCKET and type_ == socket.SCM_RIGHTS): continue - unix_fd_list.frombytes( - data[: len(data) - (len(data) % unix_fd_list.itemsize)] - ) + unix_fd_list.frombytes(data[:len(data) - (len(data) % unix_fd_list.itemsize)]) self.unix_fds.extend(list(unix_fd_list)) return msg @@ -187,9 +177,7 @@ def read_struct(self, type_: SignatureType): def read_dict_entry(self, type_: SignatureType): self.offset += -self.offset & 7 # align 8 - return self.read_argument(type_.children[0]), self.read_argument( - type_.children[1] - ) + return self.read_argument(type_.children[0]), self.read_argument(type_.children[1]) def read_array(self, type_: SignatureType): self.offset += -self.offset & 3 # align 4 for the array @@ -259,22 +247,14 @@ def _read_header(self): if endian != LITTLE_ENDIAN and endian != BIG_ENDIAN: raise InvalidMessageError( - f"Expecting endianness as the first byte, got {endian} from {buffer}" - ) + f"Expecting endianness as the first byte, got {endian} from {buffer}") if protocol_version != PROTOCOL_VERSION: - raise InvalidMessageError( - f"got unknown protocol version: {protocol_version}" - ) + raise InvalidMessageError(f"got unknown protocol version: {protocol_version}") - self.body_len, self.serial, self.header_len = UNPACK_LENGTHS[ - endian - ].unpack_from(buffer, 4) - self.msg_len = ( - self.header_len + (-self.header_len & 7) + self.body_len - ) # align 8 - if (sys.byteorder == "little" and endian == LITTLE_ENDIAN) or ( - sys.byteorder == "big" and endian == BIG_ENDIAN - ): + self.body_len, self.serial, self.header_len = UNPACK_LENGTHS[endian].unpack_from(buffer, 4) + self.msg_len = (self.header_len + (-self.header_len & 7) + self.body_len) # align 8 + if (sys.byteorder == "little" and endian == LITTLE_ENDIAN) or (sys.byteorder == "big" + and endian == BIG_ENDIAN): self.can_cast = True self.readers = self._readers_by_type[endian] @@ -317,18 +297,17 @@ def unmarshall(self): return None return self.message - _complex_parsers: Dict[ - str, Tuple[Callable[["Unmarshaller", SignatureType], Any], None, None, None] - ] = { - "b": (read_boolean, None, None, None), - "o": (read_string, None, None, None), - "s": (read_string, None, None, None), - "g": (read_signature, None, None, None), - "a": (read_array, None, None, None), - "(": (read_struct, None, None, None), - "{": (read_dict_entry, None, None, None), - "v": (read_variant, None, None, None), - } + _complex_parsers: Dict[str, Tuple[Callable[["Unmarshaller", SignatureType], Any], None, None, + None]] = { + "b": (read_boolean, None, None, None), + "o": (read_string, None, None, None), + "s": (read_string, None, None, None), + "g": (read_signature, None, None, None), + "a": (read_array, None, None, None), + "(": (read_struct, None, None, None), + "{": (read_dict_entry, None, None, None), + "v": (read_variant, None, None, None), + } _ctype_by_endian: Dict[int, Dict[str, Tuple[None, str, int, Struct]]] = { endian: { @@ -343,6 +322,12 @@ def unmarshall(self): } _readers_by_type: Dict[int, READER_TYPE] = { - BIG_ENDIAN: {**_ctype_by_endian[BIG_ENDIAN], **_complex_parsers}, - LITTLE_ENDIAN: {**_ctype_by_endian[LITTLE_ENDIAN], **_complex_parsers}, + BIG_ENDIAN: { + **_ctype_by_endian[BIG_ENDIAN], + **_complex_parsers + }, + LITTLE_ENDIAN: { + **_ctype_by_endian[LITTLE_ENDIAN], + **_complex_parsers + }, } diff --git a/dbus_next/_private/util.py b/dbus_next/_private/util.py index cf20101..0989988 100644 --- a/dbus_next/_private/util.py +++ b/dbus_next/_private/util.py @@ -101,6 +101,7 @@ def parse_annotation(annotation: str) -> str: In this case, we must eval the result which we do only when given a string constant. ''' + def raise_value_error(): raise ValueError(f'service annotations must be a string constant (got {annotation})') diff --git a/dbus_next/aio/message_bus.py b/dbus_next/aio/message_bus.py index 22a11c0..6d2b971 100644 --- a/dbus_next/aio/message_bus.py +++ b/dbus_next/aio/message_bus.py @@ -28,6 +28,7 @@ def _future_set_result(fut, result): class _MessageWriter: + def __init__(self, bus): self.messages = Queue() self.negotiate_unix_fd = bus._negotiate_unix_fd @@ -114,6 +115,7 @@ class MessageBus(BaseMessageBus): and receive messages. :vartype connected: bool """ + def __init__(self, bus_address: str = None, bus_type: BusType = BusType.SESSION, @@ -346,6 +348,7 @@ def _make_method_handler(self, interface, method): return super()._make_method_handler(interface, method) def handler(msg, send_reply): + def done(fut): with send_reply: result = fut.result() diff --git a/dbus_next/aio/proxy_object.py b/dbus_next/aio/proxy_object.py index 5214ad1..50cb502 100644 --- a/dbus_next/aio/proxy_object.py +++ b/dbus_next/aio/proxy_object.py @@ -72,7 +72,9 @@ class ProxyInterface(BaseProxyInterface): If the service returns an error for a DBus call, a :class:`DBusError ` will be raised with information about the error. """ + def _add_method(self, intr_method): + async def method_fn(*args, flags=MessageFlag.NONE): input_body, unix_fds = replace_fds_with_idx(intr_method.in_signature, list(args)) @@ -106,6 +108,7 @@ async def method_fn(*args, flags=MessageFlag.NONE): setattr(self, method_name, method_fn) def _add_property(self, intr_property): + async def property_getter(): msg = await self.bus.call( Message(destination=self.bus_name, @@ -151,6 +154,7 @@ class ProxyObject(BaseProxyObject): For more information, see the :class:`BaseProxyObject `. """ + def __init__(self, bus_name: str, path: str, introspection: Union[intr.Node, str, ET.Element], bus: BaseMessageBus): super().__init__(bus_name, path, introspection, bus, ProxyInterface) diff --git a/dbus_next/auth.py b/dbus_next/auth.py index db91c86..7d8abff 100644 --- a/dbus_next/auth.py +++ b/dbus_next/auth.py @@ -35,6 +35,7 @@ class Authenticator: :seealso: https://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol """ + def _authentication_start(self, negotiate_unix_fd=False): raise NotImplementedError( 'authentication_start() must be implemented in the inheriting class') @@ -53,6 +54,7 @@ class AuthExternal(Authenticator): :sealso: https://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol """ + def __init__(self): self.negotiate_unix_fd = False self.negotiating_fds = False @@ -84,6 +86,7 @@ class AuthAnnonymous(Authenticator): :sealso: https://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol """ + def _authentication_start(self, negotiate_unix_fd=False) -> str: if negotiate_unix_fd: raise AuthError( diff --git a/dbus_next/errors.py b/dbus_next/errors.py index b32e319..5328864 100644 --- a/dbus_next/errors.py +++ b/dbus_next/errors.py @@ -31,21 +31,25 @@ class SignalDisabledError(Exception): class InvalidBusNameError(TypeError): + def __init__(self, name): super().__init__(f'invalid bus name: {name}') class InvalidObjectPathError(TypeError): + def __init__(self, path): super().__init__(f'invalid object path: {path}') class InvalidInterfaceNameError(TypeError): + def __init__(self, name): super().__init__(f'invalid interface name: {name}') class InvalidMemberNameError(TypeError): + def __init__(self, member): super().__init__(f'invalid member name: {member}') @@ -56,6 +60,7 @@ def __init__(self, member): class DBusError(Exception): + def __init__(self, type_, text, reply=None): super().__init__(text) diff --git a/dbus_next/glib/message_bus.py b/dbus_next/glib/message_bus.py index 668e9ec..9e64f30 100644 --- a/dbus_next/glib/message_bus.py +++ b/dbus_next/glib/message_bus.py @@ -24,6 +24,7 @@ class _GLibSource: class _MessageSource(_GLibSource): + def __init__(self, bus): self.unmarshaller = None self.bus = bus @@ -54,6 +55,7 @@ def dispatch(self, callback, user_data): class _MessageWritableSource(_GLibSource): + def __init__(self, bus): self.bus = bus self.buf = b'' @@ -99,6 +101,7 @@ def dispatch(self, callback, user_data): class _AuthLineSource(_GLibSource): + def __init__(self, stream): self.stream = stream self.buf = b'' @@ -146,6 +149,7 @@ class MessageBus(BaseMessageBus): be :class:`None` until the message bus connects. :vartype unique_name: str """ + def __init__(self, bus_address: str = None, bus_type: BusType = BusType.SESSION, @@ -174,6 +178,7 @@ def connect(self, connect_notify: Callable[['MessageBus', Optional[Exception]], :class:`AuthError ` on authorization errors. :type callback: :class:`Callable` """ + def authenticate_notify(exc): if exc is not None: if connect_notify is not None: diff --git a/dbus_next/glib/proxy_object.py b/dbus_next/glib/proxy_object.py index b5887ba..42d964e 100644 --- a/dbus_next/glib/proxy_object.py +++ b/dbus_next/glib/proxy_object.py @@ -108,6 +108,7 @@ def set_callback(error: Exception) :class:`DBusError ` will be raised with information about the error. """ + def _add_method(self, intr_method): in_len = len(intr_method.in_args) out_len = len(intr_method.out_args) @@ -176,7 +177,9 @@ def callback(body, err): setattr(self, method_name_sync, method_fn_sync) def _add_property(self, intr_property): + def property_getter(callback): + def call_notify(msg, err): if err: callback(None, err) @@ -226,6 +229,7 @@ def callback(value, err): return property_value def property_setter(value, callback): + def call_notify(msg, err): if err: callback(None, err) @@ -275,6 +279,7 @@ class ProxyObject(BaseProxyObject): For more information, see the :class:`BaseProxyObject `. """ + def __init__(self, bus_name: str, path: str, introspection: Union[intr.Node, str, ET.Element], bus: BaseMessageBus): super().__init__(bus_name, path, introspection, bus, ProxyInterface) diff --git a/dbus_next/introspection.py b/dbus_next/introspection.py index d8e82a1..9fdf10f 100644 --- a/dbus_next/introspection.py +++ b/dbus_next/introspection.py @@ -28,6 +28,7 @@ class Arg: - :class:`InvalidSignatureError ` - If the signature is not valid. - :class:`InvalidIntrospectionError ` - If the signature is not a single complete type. """ + def __init__(self, signature: Union[SignatureType, str], direction: List[ArgDirection] = None, @@ -100,6 +101,7 @@ class Signal: :raises: - :class:`InvalidMemberNameError ` - If the name of the signal is not a valid member name. """ + def __init__(self, name: str, args: List[Arg] = None): if name is not None: assert_member_name_valid(name) @@ -163,6 +165,7 @@ class Method: :raises: - :class:`InvalidMemberNameError ` - If the name of this method is not valid. """ + def __init__(self, name: str, in_args: List[Arg] = [], out_args: List[Arg] = []): assert_member_name_valid(name) @@ -235,6 +238,7 @@ class Property: - :class `InvalidSignatureError ` - If the given signature is not valid. - :class: `InvalidMemberNameError ` - If the member name is not valid. """ + def __init__(self, name: str, signature: str, @@ -301,6 +305,7 @@ class Interface: :raises: - :class:`InvalidInterfaceNameError ` - If the name is not a valid interface name. """ + def __init__(self, name: str, methods: List[Method] = None, @@ -384,6 +389,7 @@ class Node: :raises: - :class:`InvalidIntrospectionError ` - If the name is not a valid node name. """ + def __init__(self, name: str = None, interfaces: List[Interface] = None, is_root: bool = True): if not is_root and not name: raise InvalidIntrospectionError('child nodes must have a "name" attribute') diff --git a/dbus_next/message.py b/dbus_next/message.py index 6685177..8b89400 100644 --- a/dbus_next/message.py +++ b/dbus_next/message.py @@ -11,7 +11,7 @@ MessageType.METHOD_CALL: ('path', 'member'), MessageType.SIGNAL: ('path', 'member', 'interface'), MessageType.ERROR: ('error_name', 'reply_serial'), - MessageType.METHOD_RETURN: ('reply_serial',), + MessageType.METHOD_RETURN: ('reply_serial', ), } @@ -61,6 +61,7 @@ class Message: - :class:`InvalidMemberNameError` - If ``member`` is not a valid member name. - :class:`InvalidInterfaceNameError` - If ``error_name`` or ``interface`` is not a valid interface name. """ + def __init__(self, destination: str = None, path: str = None, diff --git a/dbus_next/message_bus.py b/dbus_next/message_bus.py index 8bb830d..ec2fc6f 100644 --- a/dbus_next/message_bus.py +++ b/dbus_next/message_bus.py @@ -47,6 +47,7 @@ class BaseMessageBus: and receive messages. :vartype connected: bool """ + def __init__(self, bus_address: Optional[str] = None, bus_type: BusType = BusType.SESSION, @@ -627,6 +628,7 @@ def _send_reply(self, msg): bus = self class SendReply: + def __enter__(self): return self @@ -726,6 +728,7 @@ def _process_message(self, msg): del self._method_return_handlers[msg.reply_serial] def _make_method_handler(self, interface, method): + def handler(msg, send_reply): args = ServiceInterface._msg_body_to_args(msg) result = method.fn(interface, *args) diff --git a/dbus_next/proxy_object.py b/dbus_next/proxy_object.py index ddf939f..83ecbda 100644 --- a/dbus_next/proxy_object.py +++ b/dbus_next/proxy_object.py @@ -39,6 +39,7 @@ class BaseProxyInterface: :ivar bus: The message bus this proxy interface is connected to. :vartype bus: :class:`BaseMessageBus ` """ + def __init__(self, bus_name, path, introspection, bus): self.bus_name = bus_name @@ -103,6 +104,7 @@ def _message_handler(self, msg): asyncio.create_task(cb_result) def _add_signal(self, intr_signal, interface): + def on_signal_fn(fn): fn_signature = inspect.signature(fn) if not callable(fn) or len(fn_signature.parameters) != len(intr_signal.args): @@ -170,6 +172,7 @@ class BaseProxyObject: - :class:`InvalidObjectPathError ` - If the given object path is not valid. - :class:`InvalidIntrospectionError ` - If the introspection data for the node is not valid. """ + def __init__(self, bus_name: str, path: str, introspection: Union[intr.Node, str, ET.Element], bus: 'message_bus.BaseMessageBus', ProxyInterface: Type[BaseProxyInterface]): assert_object_path_valid(path) diff --git a/dbus_next/service.py b/dbus_next/service.py index b2a96cf..7c626ed 100644 --- a/dbus_next/service.py +++ b/dbus_next/service.py @@ -12,6 +12,7 @@ class _Method: + def __init__(self, fn, name, disabled=False): in_signature = '' out_signature = '' @@ -86,6 +87,7 @@ def echo_two(self, val1: 's', val2: 'u') -> 'su': @no_type_check_decorator def decorator(fn): + @wraps(fn) def wrapped(*args, **kwargs): fn(*args, **kwargs) @@ -99,6 +101,7 @@ def wrapped(*args, **kwargs): class _Signal: + def __init__(self, fn, name, disabled=False): inspection = inspect.signature(fn) @@ -180,6 +183,7 @@ def wrapped(self, *args, **kwargs): class _Property(property): + def set_options(self, options): self.options = getattr(self, 'options', {}) for k, v in options.items(): @@ -314,6 +318,7 @@ class ServiceInterface: valid interface name. :vartype name: str """ + def __init__(self, name: str): # TODO cannot be overridden by a dbus member self.name = name diff --git a/dbus_next/signature.py b/dbus_next/signature.py index 2911efb..98a50c4 100644 --- a/dbus_next/signature.py +++ b/dbus_next/signature.py @@ -368,7 +368,11 @@ class Variant: :class:`InvalidSignatureError` if the signature is not valid. :class:`SignatureBodyMismatchError` if the signature does not match the body. """ - def __init__(self, signature: Union[str, SignatureTree, SignatureType], value: Any, verify: bool = True): + + def __init__(self, + signature: Union[str, SignatureTree, SignatureType], + value: Any, + verify: bool = True): signature_str = '' signature_tree = None signature_type = None diff --git a/examples/example-service.py b/examples/example-service.py index e9833fd..19ee997 100755 --- a/examples/example-service.py +++ b/examples/example-service.py @@ -12,6 +12,7 @@ class ExampleInterface(ServiceInterface): + def __init__(self, name): super().__init__(name) self._string_prop = 'kevin' diff --git a/test/client/test_methods.py b/test/client/test_methods.py index 5f2c6c0..e7ced4a 100644 --- a/test/client/test_methods.py +++ b/test/client/test_methods.py @@ -10,6 +10,7 @@ class ExampleInterface(ServiceInterface): + def __init__(self): super().__init__('test.interface') diff --git a/test/client/test_properties.py b/test/client/test_properties.py index da06f36..1a0efc3 100644 --- a/test/client/test_properties.py +++ b/test/client/test_properties.py @@ -8,6 +8,7 @@ class ExampleInterface(ServiceInterface): + def __init__(self): super().__init__('test.interface') self._some_property = 'foo' diff --git a/test/client/test_signals.py b/test/client/test_signals.py index 848265d..9844d24 100644 --- a/test/client/test_signals.py +++ b/test/client/test_signals.py @@ -8,6 +8,7 @@ class ExampleInterface(ServiceInterface): + def __init__(self): super().__init__('test.interface') diff --git a/test/service/test_decorators.py b/test/service/test_decorators.py index 1cd236f..209d484 100644 --- a/test/service/test_decorators.py +++ b/test/service/test_decorators.py @@ -3,6 +3,7 @@ class ExampleInterface(ServiceInterface): + def __init__(self): super().__init__('test.interface') self._some_prop = 55 diff --git a/test/service/test_export.py b/test/service/test_export.py index dbed007..4086a05 100644 --- a/test/service/test_export.py +++ b/test/service/test_export.py @@ -8,6 +8,7 @@ class ExampleInterface(ServiceInterface): + def __init__(self, name): self._method_called = False super().__init__(name) diff --git a/test/service/test_methods.py b/test/service/test_methods.py index 4f528f1..f6042c4 100644 --- a/test/service/test_methods.py +++ b/test/service/test_methods.py @@ -6,6 +6,7 @@ class ExampleInterface(ServiceInterface): + def __init__(self, name): super().__init__(name) @@ -52,6 +53,7 @@ def throws_dbus_error(self): class AsyncInterface(ServiceInterface): + def __init__(self, name): super().__init__(name) diff --git a/test/service/test_properties.py b/test/service/test_properties.py index 49a9a0f..2e5f34d 100644 --- a/test/service/test_properties.py +++ b/test/service/test_properties.py @@ -7,6 +7,7 @@ class ExampleInterface(ServiceInterface): + def __init__(self, name): super().__init__(name) self._string_prop = 'hi' @@ -71,6 +72,7 @@ def do_emit_properties_changed(self): class AsyncInterface(ServiceInterface): + def __init__(self, name): super().__init__(name) self._string_prop = 'hi' diff --git a/test/service/test_signals.py b/test/service/test_signals.py index c75acb4..49578fb 100644 --- a/test/service/test_signals.py +++ b/test/service/test_signals.py @@ -9,6 +9,7 @@ class ExampleInterface(ServiceInterface): + def __init__(self, name): super().__init__(name) @@ -40,6 +41,7 @@ def test_prop(self) -> 'i': class SecondExampleInterface(ServiceInterface): + def __init__(self, name): super().__init__(name) @@ -53,6 +55,7 @@ def list_prop(self) -> 'ai': class ExpectMessage: + def __init__(self, bus1, bus2, interface_name, timeout=1): self.future = asyncio.get_event_loop().create_future() self.bus1 = bus1 diff --git a/test/service/test_standard_interfaces.py b/test/service/test_standard_interfaces.py index 7ad6f35..abb693a 100644 --- a/test/service/test_standard_interfaces.py +++ b/test/service/test_standard_interfaces.py @@ -10,11 +10,13 @@ class ExampleInterface(ServiceInterface): + def __init__(self, name): super().__init__(name) class ExampleComplexInterface(ServiceInterface): + def __init__(self, name): self._foo = 42 self._bar = 'str' diff --git a/test/test_big_message.py b/test/test_big_message.py index 31b7af9..dff784d 100644 --- a/test/test_big_message.py +++ b/test/test_big_message.py @@ -8,6 +8,7 @@ class ExampleInterface(ServiceInterface): + def __init__(self): super().__init__('example.interface') diff --git a/test/test_fd_passing.py b/test/test_fd_passing.py index 28331d3..eb10263 100644 --- a/test/test_fd_passing.py +++ b/test/test_fd_passing.py @@ -13,6 +13,7 @@ def open_file(): class ExampleInterface(ServiceInterface): + def __init__(self, name): super().__init__(name) self.fds = [] diff --git a/test/test_marshaller.py b/test/test_marshaller.py index b14e2b7..efefaa5 100644 --- a/test/test_marshaller.py +++ b/test/test_marshaller.py @@ -58,6 +58,7 @@ def replace_variants(type_, item): def json_dump(what): + def dumper(obj): try: return obj.toJSON() @@ -113,19 +114,18 @@ def test_unmarshalling_with_table(unmarshall_table): message.body = body for attr in [ - "body", - "signature", - "message_type", - "destination", - "path", - "interface", - "member", - "flags", - "serial", + "body", + "signature", + "message_type", + "destination", + "path", + "interface", + "member", + "flags", + "serial", ]: - assert getattr(unmarshaller.message, attr) == getattr( - message, attr - ), f"attr doesnt match: {attr}" + assert getattr(unmarshaller.message, + attr) == getattr(message, attr), f"attr doesnt match: {attr}" def test_unmarshall_can_resume(): @@ -136,8 +136,7 @@ def test_unmarshall_can_resume(): "746f702e444275732e50726f7065727469657300030173001100000050726f706572746965734368616e" "67656400000000000000080167000873617b73767d617300000007017300040000003a312e3400000000" "110000006f72672e626c75657a2e446576696365310000000e0000000000000004000000525353490001" - "6e00a7ff000000000000" - ) + "6e00a7ff000000000000") message_bytes = bytes.fromhex(bluez_rssi_message) class SlowStream(io.IOBase): From f833e09385d560981d02a5d97b67317119f61dd8 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 11 Sep 2022 12:32:03 -0500 Subject: [PATCH 15/17] rewrite to make both yapf and flake8 happy since they do not agree on the formatting --- dbus_next/_private/unmarshaller.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dbus_next/_private/unmarshaller.py b/dbus_next/_private/unmarshaller.py index 8784088..f5ed258 100644 --- a/dbus_next/_private/unmarshaller.py +++ b/dbus_next/_private/unmarshaller.py @@ -21,6 +21,8 @@ UNPACK_SYMBOL = {LITTLE_ENDIAN: "<", BIG_ENDIAN: ">"} UNPACK_LENGTHS = {BIG_ENDIAN: Struct(">III"), LITTLE_ENDIAN: Struct(" Date: Sun, 11 Sep 2022 12:32:33 -0500 Subject: [PATCH 16/17] cheapest check first --- dbus_next/_private/unmarshaller.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dbus_next/_private/unmarshaller.py b/dbus_next/_private/unmarshaller.py index f5ed258..55b9884 100644 --- a/dbus_next/_private/unmarshaller.py +++ b/dbus_next/_private/unmarshaller.py @@ -255,9 +255,9 @@ def _read_header(self): self.body_len, self.serial, self.header_len = UNPACK_LENGTHS[endian].unpack_from(buffer, 4) self.msg_len = (self.header_len + (-self.header_len & 7) + self.body_len) # align 8 - if endian == BIG_ENDIAN and IS_BIG_ENDIAN: + if IS_BIG_ENDIAN and endian == BIG_ENDIAN: self.can_cast = True - elif endian == LITTLE_ENDIAN and IS_LITTLE_ENDIAN: + elif IS_LITTLE_ENDIAN and endian == LITTLE_ENDIAN: self.can_cast = True self.readers = self._readers_by_type[endian] From c26ba7e2ef543d0590a99550bdde51036c415659 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 11 Sep 2022 12:36:07 -0500 Subject: [PATCH 17/17] reformat with older version of yapf --- dbus_next/_private/marshaller.py | 1 - dbus_next/_private/util.py | 1 - dbus_next/aio/message_bus.py | 3 --- dbus_next/aio/proxy_object.py | 4 ---- dbus_next/auth.py | 3 --- dbus_next/errors.py | 5 ----- dbus_next/glib/message_bus.py | 5 ----- dbus_next/glib/proxy_object.py | 5 ----- dbus_next/introspection.py | 6 ------ dbus_next/message.py | 1 - dbus_next/message_bus.py | 3 --- dbus_next/proxy_object.py | 3 --- dbus_next/service.py | 5 ----- dbus_next/signature.py | 2 -- examples/example-service.py | 1 - test/client/test_methods.py | 1 - test/client/test_properties.py | 1 - test/client/test_signals.py | 1 - test/service/test_decorators.py | 1 - test/service/test_export.py | 1 - test/service/test_methods.py | 2 -- test/service/test_properties.py | 2 -- test/service/test_signals.py | 3 --- test/service/test_standard_interfaces.py | 2 -- test/test_big_message.py | 1 - test/test_fd_passing.py | 1 - test/test_marshaller.py | 2 -- 27 files changed, 66 deletions(-) diff --git a/dbus_next/_private/marshaller.py b/dbus_next/_private/marshaller.py index 706f430..db71dee 100644 --- a/dbus_next/_private/marshaller.py +++ b/dbus_next/_private/marshaller.py @@ -3,7 +3,6 @@ class Marshaller: - def __init__(self, signature, body): self.signature_tree = SignatureTree._get(signature) self.signature_tree.verify(body) diff --git a/dbus_next/_private/util.py b/dbus_next/_private/util.py index 0989988..cf20101 100644 --- a/dbus_next/_private/util.py +++ b/dbus_next/_private/util.py @@ -101,7 +101,6 @@ def parse_annotation(annotation: str) -> str: In this case, we must eval the result which we do only when given a string constant. ''' - def raise_value_error(): raise ValueError(f'service annotations must be a string constant (got {annotation})') diff --git a/dbus_next/aio/message_bus.py b/dbus_next/aio/message_bus.py index 6d2b971..22a11c0 100644 --- a/dbus_next/aio/message_bus.py +++ b/dbus_next/aio/message_bus.py @@ -28,7 +28,6 @@ def _future_set_result(fut, result): class _MessageWriter: - def __init__(self, bus): self.messages = Queue() self.negotiate_unix_fd = bus._negotiate_unix_fd @@ -115,7 +114,6 @@ class MessageBus(BaseMessageBus): and receive messages. :vartype connected: bool """ - def __init__(self, bus_address: str = None, bus_type: BusType = BusType.SESSION, @@ -348,7 +346,6 @@ def _make_method_handler(self, interface, method): return super()._make_method_handler(interface, method) def handler(msg, send_reply): - def done(fut): with send_reply: result = fut.result() diff --git a/dbus_next/aio/proxy_object.py b/dbus_next/aio/proxy_object.py index 50cb502..5214ad1 100644 --- a/dbus_next/aio/proxy_object.py +++ b/dbus_next/aio/proxy_object.py @@ -72,9 +72,7 @@ class ProxyInterface(BaseProxyInterface): If the service returns an error for a DBus call, a :class:`DBusError ` will be raised with information about the error. """ - def _add_method(self, intr_method): - async def method_fn(*args, flags=MessageFlag.NONE): input_body, unix_fds = replace_fds_with_idx(intr_method.in_signature, list(args)) @@ -108,7 +106,6 @@ async def method_fn(*args, flags=MessageFlag.NONE): setattr(self, method_name, method_fn) def _add_property(self, intr_property): - async def property_getter(): msg = await self.bus.call( Message(destination=self.bus_name, @@ -154,7 +151,6 @@ class ProxyObject(BaseProxyObject): For more information, see the :class:`BaseProxyObject `. """ - def __init__(self, bus_name: str, path: str, introspection: Union[intr.Node, str, ET.Element], bus: BaseMessageBus): super().__init__(bus_name, path, introspection, bus, ProxyInterface) diff --git a/dbus_next/auth.py b/dbus_next/auth.py index 7d8abff..db91c86 100644 --- a/dbus_next/auth.py +++ b/dbus_next/auth.py @@ -35,7 +35,6 @@ class Authenticator: :seealso: https://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol """ - def _authentication_start(self, negotiate_unix_fd=False): raise NotImplementedError( 'authentication_start() must be implemented in the inheriting class') @@ -54,7 +53,6 @@ class AuthExternal(Authenticator): :sealso: https://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol """ - def __init__(self): self.negotiate_unix_fd = False self.negotiating_fds = False @@ -86,7 +84,6 @@ class AuthAnnonymous(Authenticator): :sealso: https://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol """ - def _authentication_start(self, negotiate_unix_fd=False) -> str: if negotiate_unix_fd: raise AuthError( diff --git a/dbus_next/errors.py b/dbus_next/errors.py index 5328864..b32e319 100644 --- a/dbus_next/errors.py +++ b/dbus_next/errors.py @@ -31,25 +31,21 @@ class SignalDisabledError(Exception): class InvalidBusNameError(TypeError): - def __init__(self, name): super().__init__(f'invalid bus name: {name}') class InvalidObjectPathError(TypeError): - def __init__(self, path): super().__init__(f'invalid object path: {path}') class InvalidInterfaceNameError(TypeError): - def __init__(self, name): super().__init__(f'invalid interface name: {name}') class InvalidMemberNameError(TypeError): - def __init__(self, member): super().__init__(f'invalid member name: {member}') @@ -60,7 +56,6 @@ def __init__(self, member): class DBusError(Exception): - def __init__(self, type_, text, reply=None): super().__init__(text) diff --git a/dbus_next/glib/message_bus.py b/dbus_next/glib/message_bus.py index 9e64f30..668e9ec 100644 --- a/dbus_next/glib/message_bus.py +++ b/dbus_next/glib/message_bus.py @@ -24,7 +24,6 @@ class _GLibSource: class _MessageSource(_GLibSource): - def __init__(self, bus): self.unmarshaller = None self.bus = bus @@ -55,7 +54,6 @@ def dispatch(self, callback, user_data): class _MessageWritableSource(_GLibSource): - def __init__(self, bus): self.bus = bus self.buf = b'' @@ -101,7 +99,6 @@ def dispatch(self, callback, user_data): class _AuthLineSource(_GLibSource): - def __init__(self, stream): self.stream = stream self.buf = b'' @@ -149,7 +146,6 @@ class MessageBus(BaseMessageBus): be :class:`None` until the message bus connects. :vartype unique_name: str """ - def __init__(self, bus_address: str = None, bus_type: BusType = BusType.SESSION, @@ -178,7 +174,6 @@ def connect(self, connect_notify: Callable[['MessageBus', Optional[Exception]], :class:`AuthError ` on authorization errors. :type callback: :class:`Callable` """ - def authenticate_notify(exc): if exc is not None: if connect_notify is not None: diff --git a/dbus_next/glib/proxy_object.py b/dbus_next/glib/proxy_object.py index 42d964e..b5887ba 100644 --- a/dbus_next/glib/proxy_object.py +++ b/dbus_next/glib/proxy_object.py @@ -108,7 +108,6 @@ def set_callback(error: Exception) :class:`DBusError ` will be raised with information about the error. """ - def _add_method(self, intr_method): in_len = len(intr_method.in_args) out_len = len(intr_method.out_args) @@ -177,9 +176,7 @@ def callback(body, err): setattr(self, method_name_sync, method_fn_sync) def _add_property(self, intr_property): - def property_getter(callback): - def call_notify(msg, err): if err: callback(None, err) @@ -229,7 +226,6 @@ def callback(value, err): return property_value def property_setter(value, callback): - def call_notify(msg, err): if err: callback(None, err) @@ -279,7 +275,6 @@ class ProxyObject(BaseProxyObject): For more information, see the :class:`BaseProxyObject `. """ - def __init__(self, bus_name: str, path: str, introspection: Union[intr.Node, str, ET.Element], bus: BaseMessageBus): super().__init__(bus_name, path, introspection, bus, ProxyInterface) diff --git a/dbus_next/introspection.py b/dbus_next/introspection.py index 9fdf10f..d8e82a1 100644 --- a/dbus_next/introspection.py +++ b/dbus_next/introspection.py @@ -28,7 +28,6 @@ class Arg: - :class:`InvalidSignatureError ` - If the signature is not valid. - :class:`InvalidIntrospectionError ` - If the signature is not a single complete type. """ - def __init__(self, signature: Union[SignatureType, str], direction: List[ArgDirection] = None, @@ -101,7 +100,6 @@ class Signal: :raises: - :class:`InvalidMemberNameError ` - If the name of the signal is not a valid member name. """ - def __init__(self, name: str, args: List[Arg] = None): if name is not None: assert_member_name_valid(name) @@ -165,7 +163,6 @@ class Method: :raises: - :class:`InvalidMemberNameError ` - If the name of this method is not valid. """ - def __init__(self, name: str, in_args: List[Arg] = [], out_args: List[Arg] = []): assert_member_name_valid(name) @@ -238,7 +235,6 @@ class Property: - :class `InvalidSignatureError ` - If the given signature is not valid. - :class: `InvalidMemberNameError ` - If the member name is not valid. """ - def __init__(self, name: str, signature: str, @@ -305,7 +301,6 @@ class Interface: :raises: - :class:`InvalidInterfaceNameError ` - If the name is not a valid interface name. """ - def __init__(self, name: str, methods: List[Method] = None, @@ -389,7 +384,6 @@ class Node: :raises: - :class:`InvalidIntrospectionError ` - If the name is not a valid node name. """ - def __init__(self, name: str = None, interfaces: List[Interface] = None, is_root: bool = True): if not is_root and not name: raise InvalidIntrospectionError('child nodes must have a "name" attribute') diff --git a/dbus_next/message.py b/dbus_next/message.py index 8b89400..c43abd8 100644 --- a/dbus_next/message.py +++ b/dbus_next/message.py @@ -61,7 +61,6 @@ class Message: - :class:`InvalidMemberNameError` - If ``member`` is not a valid member name. - :class:`InvalidInterfaceNameError` - If ``error_name`` or ``interface`` is not a valid interface name. """ - def __init__(self, destination: str = None, path: str = None, diff --git a/dbus_next/message_bus.py b/dbus_next/message_bus.py index ec2fc6f..8bb830d 100644 --- a/dbus_next/message_bus.py +++ b/dbus_next/message_bus.py @@ -47,7 +47,6 @@ class BaseMessageBus: and receive messages. :vartype connected: bool """ - def __init__(self, bus_address: Optional[str] = None, bus_type: BusType = BusType.SESSION, @@ -628,7 +627,6 @@ def _send_reply(self, msg): bus = self class SendReply: - def __enter__(self): return self @@ -728,7 +726,6 @@ def _process_message(self, msg): del self._method_return_handlers[msg.reply_serial] def _make_method_handler(self, interface, method): - def handler(msg, send_reply): args = ServiceInterface._msg_body_to_args(msg) result = method.fn(interface, *args) diff --git a/dbus_next/proxy_object.py b/dbus_next/proxy_object.py index 83ecbda..ddf939f 100644 --- a/dbus_next/proxy_object.py +++ b/dbus_next/proxy_object.py @@ -39,7 +39,6 @@ class BaseProxyInterface: :ivar bus: The message bus this proxy interface is connected to. :vartype bus: :class:`BaseMessageBus ` """ - def __init__(self, bus_name, path, introspection, bus): self.bus_name = bus_name @@ -104,7 +103,6 @@ def _message_handler(self, msg): asyncio.create_task(cb_result) def _add_signal(self, intr_signal, interface): - def on_signal_fn(fn): fn_signature = inspect.signature(fn) if not callable(fn) or len(fn_signature.parameters) != len(intr_signal.args): @@ -172,7 +170,6 @@ class BaseProxyObject: - :class:`InvalidObjectPathError ` - If the given object path is not valid. - :class:`InvalidIntrospectionError ` - If the introspection data for the node is not valid. """ - def __init__(self, bus_name: str, path: str, introspection: Union[intr.Node, str, ET.Element], bus: 'message_bus.BaseMessageBus', ProxyInterface: Type[BaseProxyInterface]): assert_object_path_valid(path) diff --git a/dbus_next/service.py b/dbus_next/service.py index 7c626ed..b2a96cf 100644 --- a/dbus_next/service.py +++ b/dbus_next/service.py @@ -12,7 +12,6 @@ class _Method: - def __init__(self, fn, name, disabled=False): in_signature = '' out_signature = '' @@ -87,7 +86,6 @@ def echo_two(self, val1: 's', val2: 'u') -> 'su': @no_type_check_decorator def decorator(fn): - @wraps(fn) def wrapped(*args, **kwargs): fn(*args, **kwargs) @@ -101,7 +99,6 @@ def wrapped(*args, **kwargs): class _Signal: - def __init__(self, fn, name, disabled=False): inspection = inspect.signature(fn) @@ -183,7 +180,6 @@ def wrapped(self, *args, **kwargs): class _Property(property): - def set_options(self, options): self.options = getattr(self, 'options', {}) for k, v in options.items(): @@ -318,7 +314,6 @@ class ServiceInterface: valid interface name. :vartype name: str """ - def __init__(self, name: str): # TODO cannot be overridden by a dbus member self.name = name diff --git a/dbus_next/signature.py b/dbus_next/signature.py index 98a50c4..dd83bed 100644 --- a/dbus_next/signature.py +++ b/dbus_next/signature.py @@ -301,7 +301,6 @@ class SignatureTree: :raises: :class:`InvalidSignatureError` if the given signature is not valid. """ - @staticmethod @lru_cache(maxsize=None) def _get(signature: str = '') -> "SignatureTree": @@ -368,7 +367,6 @@ class Variant: :class:`InvalidSignatureError` if the signature is not valid. :class:`SignatureBodyMismatchError` if the signature does not match the body. """ - def __init__(self, signature: Union[str, SignatureTree, SignatureType], value: Any, diff --git a/examples/example-service.py b/examples/example-service.py index 19ee997..e9833fd 100755 --- a/examples/example-service.py +++ b/examples/example-service.py @@ -12,7 +12,6 @@ class ExampleInterface(ServiceInterface): - def __init__(self, name): super().__init__(name) self._string_prop = 'kevin' diff --git a/test/client/test_methods.py b/test/client/test_methods.py index e7ced4a..5f2c6c0 100644 --- a/test/client/test_methods.py +++ b/test/client/test_methods.py @@ -10,7 +10,6 @@ class ExampleInterface(ServiceInterface): - def __init__(self): super().__init__('test.interface') diff --git a/test/client/test_properties.py b/test/client/test_properties.py index 1a0efc3..da06f36 100644 --- a/test/client/test_properties.py +++ b/test/client/test_properties.py @@ -8,7 +8,6 @@ class ExampleInterface(ServiceInterface): - def __init__(self): super().__init__('test.interface') self._some_property = 'foo' diff --git a/test/client/test_signals.py b/test/client/test_signals.py index 9844d24..848265d 100644 --- a/test/client/test_signals.py +++ b/test/client/test_signals.py @@ -8,7 +8,6 @@ class ExampleInterface(ServiceInterface): - def __init__(self): super().__init__('test.interface') diff --git a/test/service/test_decorators.py b/test/service/test_decorators.py index 209d484..1cd236f 100644 --- a/test/service/test_decorators.py +++ b/test/service/test_decorators.py @@ -3,7 +3,6 @@ class ExampleInterface(ServiceInterface): - def __init__(self): super().__init__('test.interface') self._some_prop = 55 diff --git a/test/service/test_export.py b/test/service/test_export.py index 4086a05..dbed007 100644 --- a/test/service/test_export.py +++ b/test/service/test_export.py @@ -8,7 +8,6 @@ class ExampleInterface(ServiceInterface): - def __init__(self, name): self._method_called = False super().__init__(name) diff --git a/test/service/test_methods.py b/test/service/test_methods.py index f6042c4..4f528f1 100644 --- a/test/service/test_methods.py +++ b/test/service/test_methods.py @@ -6,7 +6,6 @@ class ExampleInterface(ServiceInterface): - def __init__(self, name): super().__init__(name) @@ -53,7 +52,6 @@ def throws_dbus_error(self): class AsyncInterface(ServiceInterface): - def __init__(self, name): super().__init__(name) diff --git a/test/service/test_properties.py b/test/service/test_properties.py index 2e5f34d..49a9a0f 100644 --- a/test/service/test_properties.py +++ b/test/service/test_properties.py @@ -7,7 +7,6 @@ class ExampleInterface(ServiceInterface): - def __init__(self, name): super().__init__(name) self._string_prop = 'hi' @@ -72,7 +71,6 @@ def do_emit_properties_changed(self): class AsyncInterface(ServiceInterface): - def __init__(self, name): super().__init__(name) self._string_prop = 'hi' diff --git a/test/service/test_signals.py b/test/service/test_signals.py index 49578fb..c75acb4 100644 --- a/test/service/test_signals.py +++ b/test/service/test_signals.py @@ -9,7 +9,6 @@ class ExampleInterface(ServiceInterface): - def __init__(self, name): super().__init__(name) @@ -41,7 +40,6 @@ def test_prop(self) -> 'i': class SecondExampleInterface(ServiceInterface): - def __init__(self, name): super().__init__(name) @@ -55,7 +53,6 @@ def list_prop(self) -> 'ai': class ExpectMessage: - def __init__(self, bus1, bus2, interface_name, timeout=1): self.future = asyncio.get_event_loop().create_future() self.bus1 = bus1 diff --git a/test/service/test_standard_interfaces.py b/test/service/test_standard_interfaces.py index abb693a..7ad6f35 100644 --- a/test/service/test_standard_interfaces.py +++ b/test/service/test_standard_interfaces.py @@ -10,13 +10,11 @@ class ExampleInterface(ServiceInterface): - def __init__(self, name): super().__init__(name) class ExampleComplexInterface(ServiceInterface): - def __init__(self, name): self._foo = 42 self._bar = 'str' diff --git a/test/test_big_message.py b/test/test_big_message.py index dff784d..31b7af9 100644 --- a/test/test_big_message.py +++ b/test/test_big_message.py @@ -8,7 +8,6 @@ class ExampleInterface(ServiceInterface): - def __init__(self): super().__init__('example.interface') diff --git a/test/test_fd_passing.py b/test/test_fd_passing.py index eb10263..28331d3 100644 --- a/test/test_fd_passing.py +++ b/test/test_fd_passing.py @@ -13,7 +13,6 @@ def open_file(): class ExampleInterface(ServiceInterface): - def __init__(self, name): super().__init__(name) self.fds = [] diff --git a/test/test_marshaller.py b/test/test_marshaller.py index efefaa5..f09cf49 100644 --- a/test/test_marshaller.py +++ b/test/test_marshaller.py @@ -58,7 +58,6 @@ def replace_variants(type_, item): def json_dump(what): - def dumper(obj): try: return obj.toJSON() @@ -141,7 +140,6 @@ def test_unmarshall_can_resume(): class SlowStream(io.IOBase): """A fake stream that will only give us one byte at a time.""" - def __init__(self): self.data = message_bytes self.pos = 0