""" Custom exceptions for laser control module. Provides a hierarchy of exceptions for different error conditions that may occur during laser control operations. """ class LaserControlError(Exception): """Base exception for all laser control errors.""" pass class ValidationError(LaserControlError, ValueError): """Base exception for validation errors.""" pass class CommunicationError(LaserControlError): """Base exception for communication errors.""" pass class PortBusyError(CommunicationError): """Raised when the serial port is already held by another program. A laser controller is a single half-duplex request/response bus: only one process may own it at a time. When the port is opened exclusively (``exclusive=True``), a second exclusive open fails with this error instead of silently sharing the bus and corrupting both sides' traffic. """ def __init__(self, port: str | None = None): target = f"'{port}'" if port else "the laser controller port" super().__init__( f"Serial port {target} is busy — another program is already using " f"the laser controller. Close it first (only one program may own the " f"port at a time)." ) class ProtocolError(CommunicationError): """Exception raised for protocol-level errors.""" def __init__(self, message: str): super().__init__(f"Protocol error: {message}")