diff --git a/can/interfaces/udp_multicast/bus.py b/can/interfaces/udp_multicast/bus.py index ee6a6e1ee..86a78a1ff 100644 --- a/can/interfaces/udp_multicast/bus.py +++ b/can/interfaces/udp_multicast/bus.py @@ -92,7 +92,9 @@ def __init__( check_msgpack_installed() if receive_own_messages: - raise NotImplementedError("receiving own messages is not yet implemented") + raise can.CanInterfaceNotImplementedError( + "receiving own messages is not yet implemented" + ) super().__init__(channel, **kwargs) @@ -105,7 +107,14 @@ def _recv_internal(self, timeout: Optional[float]): return None, False data, _, timestamp = result - can_message = unpack_message(data, replace={"timestamp": timestamp}) + try: + can_message = unpack_message( + data, replace={"timestamp": timestamp}, check=True + ) + except Exception as exception: + raise can.CanOperationError( + "could not unpack received message" + ) from exception if not self.is_fd and can_message.is_fd: return None, False @@ -114,7 +123,9 @@ def _recv_internal(self, timeout: Optional[float]): def send(self, message: can.Message, timeout: Optional[float] = None) -> None: if not self.is_fd and message.is_fd: - raise RuntimeError("cannot send FD message over bus with CAN FD disabled") + raise can.CanOperationError( + "cannot send FD message over bus with CAN FD disabled" + ) data = pack_message(message) self._multicast.send(data, timeout) @@ -149,7 +160,10 @@ def _detect_available_configs() -> List[AutoDetectedConfig]: class GeneralPurposeUdpMulticastBus: - """A general purpose send and receive handler for multicast over IP/UDP.""" + """A general purpose send and receive handler for multicast over IP/UDP. + + However, it raises CAN-specific exceptions for convenience. + """ def __init__( self, group: str, port: int, hop_limit: int, max_buffer: int = 4096 @@ -178,7 +192,9 @@ def __init__( if sock is not None: self._socket = sock else: - raise RuntimeError("could not connect to a multicast IP network") + raise can.CanInitializationError( + "could not connect to a multicast IP network" + ) # used in recv() self.received_timestamp_struct = "@ll" @@ -193,8 +209,10 @@ def _create_socket(self, address_family: socket.AddressFamily) -> socket.socket: """Creates a new socket. This might fail and raise an exception! :param address_family: whether this is of type `socket.AF_INET` or `socket.AF_INET6` - :raises OSError: if the socket could not be opened or configured correctly; in this case, it is - guaranteed to be closed/cleaned up + + :raises can.CanInitializationError: + if the socket could not be opened or configured correctly; in this case, it is + guaranteed to be closed/cleaned up """ # create the UDP socket # this might already fail but then there is nothing to clean up @@ -243,7 +261,9 @@ def _create_socket(self, address_family: socket.AddressFamily) -> socket.socket: log.warning("Could not close partly configured socket: %s", close_error) # still raise the error - raise error + raise can.CanInitializationError( + "could not create or configure socket" + ) from error def send(self, data: bytes, timeout: Optional[float] = None) -> None: """Send data to all group members. This call blocks. @@ -283,7 +303,9 @@ def recv( ready_receive_sockets, _, _ = select.select([self._socket], [], [], timeout) except socket.error as exc: # something bad (not a timeout) happened (e.g. the interface went down) - raise can.CanError(f"Failed to wait for IP/UDP socket: {exc}") + raise can.CanOperationError( + f"Failed to wait for IP/UDP socket: {exc}" + ) from exc if ready_receive_sockets: # not empty # fetch data & source address diff --git a/can/interfaces/udp_multicast/utils.py b/can/interfaces/udp_multicast/utils.py index dad368f0b..2658bf0a9 100644 --- a/can/interfaces/udp_multicast/utils.py +++ b/can/interfaces/udp_multicast/utils.py @@ -7,6 +7,7 @@ from typing import Optional from can import Message +from can import CanInterfaceNotImplementedError from can.typechecking import ReadableBytesLike try: @@ -16,9 +17,9 @@ def check_msgpack_installed() -> None: - """Raises a `RuntimeError` if `msgpack` is not installed.""" + """Raises a :class:`can.CanInterfaceNotImplementedError` if `msgpack` is not installed.""" if msgpack is None: - raise RuntimeError("msgpack not installed") + raise CanInterfaceNotImplementedError("msgpack not installed") def pack_message(message: Message) -> bytes: