Skip to content

Commit 9080c47

Browse files
authored
Complete broken PR #1156 (Specific Exceptions: Adapting slcan interface) (#1166)
* Complete switch to new exceptions * Format code * Fix TestBaseRotatingLogger
1 parent 8ab55e8 commit 9080c47

File tree

2 files changed

+64
-48
lines changed

2 files changed

+64
-48
lines changed

can/interfaces/slcan.py

+62-43
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@
99
import logging
1010

1111
from can import BusABC, Message
12-
from ..exceptions import CanInterfaceNotImplementedError, CanOperationError
12+
from ..exceptions import (
13+
CanInterfaceNotImplementedError,
14+
CanInitializationError,
15+
CanOperationError,
16+
error_check,
17+
)
1318
from can import typechecking
1419

1520

@@ -62,8 +67,6 @@ def __init__(
6267
**kwargs: Any,
6368
) -> None:
6469
"""
65-
:raise ValueError: if both *bitrate* and *btr* are set
66-
6770
:param str channel:
6871
port of underlying serial or usb device (e.g. ``/dev/ttyUSB0``, ``COM8``, ...)
6972
Must not be empty. Can also end with ``@115200`` (or similarly) to specify the baudrate.
@@ -79,48 +82,57 @@ def __init__(
7982
Time to wait in seconds after opening serial connection
8083
:param rtscts:
8184
turn hardware handshake (RTS/CTS) on and off
85+
86+
:raise ValueError: if both ``bitrate`` and ``btr`` are set or the channel is invalid
87+
:raise CanInterfaceNotImplementedError: if the serial module is missing
88+
:raise CanInitializationError: if the underlying serial connection could not be established
8289
"""
8390
if serial is None:
8491
raise CanInterfaceNotImplementedError("The serial module is not installed")
8592

8693
if not channel: # if None or empty
87-
raise TypeError("Must specify a serial port.")
94+
raise ValueError("Must specify a serial port.")
8895
if "@" in channel:
8996
(channel, baudrate) = channel.split("@")
9097
ttyBaudrate = int(baudrate)
91-
self.serialPortOrig = serial.serial_for_url(
92-
channel, baudrate=ttyBaudrate, rtscts=rtscts
93-
)
98+
99+
with error_check(exception_type=CanInitializationError):
100+
self.serialPortOrig = serial.serial_for_url(
101+
channel, baudrate=ttyBaudrate, rtscts=rtscts
102+
)
94103

95104
self._buffer = bytearray()
96105

97106
time.sleep(sleep_after_open)
98107

99-
if bitrate is not None and btr is not None:
100-
raise ValueError("Bitrate and btr mutually exclusive.")
101-
if bitrate is not None:
102-
self.set_bitrate(bitrate)
103-
if btr is not None:
104-
self.set_bitrate_reg(btr)
105-
self.open()
108+
with error_check(exception_type=CanInitializationError):
109+
if bitrate is not None and btr is not None:
110+
raise ValueError("Bitrate and btr mutually exclusive.")
111+
if bitrate is not None:
112+
self.set_bitrate(bitrate)
113+
if btr is not None:
114+
self.set_bitrate_reg(btr)
115+
self.open()
106116

107117
super().__init__(
108118
channel, ttyBaudrate=115200, bitrate=None, rtscts=False, **kwargs
109119
)
110120

111121
def set_bitrate(self, bitrate: int) -> None:
112122
"""
113-
:raise ValueError: if both *bitrate* is not among the possible values
114-
115123
:param bitrate:
116124
Bitrate in bit/s
125+
126+
:raise ValueError: if ``bitrate`` is not among the possible values
117127
"""
118-
self.close()
119128
if bitrate in self._BITRATES:
120-
self._write(self._BITRATES[bitrate])
129+
bitrate_code = self._BITRATES[bitrate]
121130
else:
122131
bitrates = ", ".join(str(k) for k in self._BITRATES.keys())
123132
raise ValueError(f"Invalid bitrate, choose one of {bitrates}.")
133+
134+
self.close()
135+
self._write(bitrate_code)
124136
self.open()
125137

126138
def set_bitrate_reg(self, btr: str) -> None:
@@ -133,33 +145,38 @@ def set_bitrate_reg(self, btr: str) -> None:
133145
self.open()
134146

135147
def _write(self, string: str) -> None:
136-
self.serialPortOrig.write(string.encode() + self.LINE_TERMINATOR)
137-
self.serialPortOrig.flush()
148+
with error_check("Could not write to serial device"):
149+
self.serialPortOrig.write(string.encode() + self.LINE_TERMINATOR)
150+
self.serialPortOrig.flush()
138151

139152
def _read(self, timeout: Optional[float]) -> Optional[str]:
140153

141-
# first read what is already in receive buffer
142-
while self.serialPortOrig.in_waiting:
143-
self._buffer += self.serialPortOrig.read()
144-
# if we still don't have a complete message, do a blocking read
145-
start = time.time()
146-
time_left = timeout
147-
while not (ord(self._OK) in self._buffer or ord(self._ERROR) in self._buffer):
148-
self.serialPortOrig.timeout = time_left
149-
byte = self.serialPortOrig.read()
150-
if byte:
151-
self._buffer += byte
152-
# if timeout is None, try indefinitely
153-
if timeout is None:
154-
continue
155-
# try next one only if there still is time, and with
156-
# reduced timeout
157-
else:
158-
time_left = timeout - (time.time() - start)
159-
if time_left > 0:
154+
with error_check("Could not read from serial device"):
155+
# first read what is already in receive buffer
156+
while self.serialPortOrig.in_waiting:
157+
self._buffer += self.serialPortOrig.read()
158+
# if we still don't have a complete message, do a blocking read
159+
start = time.time()
160+
time_left = timeout
161+
while not (
162+
ord(self._OK) in self._buffer or ord(self._ERROR) in self._buffer
163+
):
164+
self.serialPortOrig.timeout = time_left
165+
byte = self.serialPortOrig.read()
166+
if byte:
167+
self._buffer += byte
168+
# if timeout is None, try indefinitely
169+
if timeout is None:
160170
continue
171+
# try next one only if there still is time, and with
172+
# reduced timeout
161173
else:
162-
return None
174+
time_left = timeout - (time.time() - start)
175+
if time_left > 0:
176+
continue
177+
else:
178+
return None
179+
163180
# return first message
164181
for i in range(len(self._buffer)):
165182
if self._buffer[i] == ord(self._OK) or self._buffer[i] == ord(self._ERROR):
@@ -170,8 +187,9 @@ def _read(self, timeout: Optional[float]) -> Optional[str]:
170187

171188
def flush(self) -> None:
172189
del self._buffer[:]
173-
while self.serialPortOrig.in_waiting:
174-
self.serialPortOrig.read()
190+
with error_check("Could not flush"):
191+
while self.serialPortOrig.in_waiting:
192+
self.serialPortOrig.read()
175193

176194
def open(self) -> None:
177195
self._write("O")
@@ -247,7 +265,8 @@ def send(self, msg: Message, timeout: Optional[float] = None) -> None:
247265

248266
def shutdown(self) -> None:
249267
self.close()
250-
self.serialPortOrig.close()
268+
with error_check("Could not close serial socket"):
269+
self.serialPortOrig.close()
251270

252271
def fileno(self) -> int:
253272
try:

test/test_rotating_loggers.py

+2-5
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,8 @@
66

77
import os
88
from pathlib import Path
9-
import tempfile
109
from unittest.mock import Mock
1110

12-
import pytest
13-
1411
import can
1512
from .data.example_data import generate_message
1613

@@ -90,7 +87,7 @@ def test_rotate_without_rotator(self, tmp_path):
9087
assert os.path.exists(source) is False
9188
assert os.path.exists(dest) is False
9289

93-
logger_instance._get_new_writer(source)
90+
logger_instance._writer = logger_instance._get_new_writer(source)
9491
logger_instance.stop()
9592

9693
assert os.path.exists(source) is True
@@ -113,7 +110,7 @@ def test_rotate_with_rotator(self, tmp_path):
113110
assert os.path.exists(source) is False
114111
assert os.path.exists(dest) is False
115112

116-
logger_instance._get_new_writer(source)
113+
logger_instance._writer = logger_instance._get_new_writer(source)
117114
logger_instance.stop()
118115

119116
assert os.path.exists(source) is True

0 commit comments

Comments
 (0)