Skip to content

Commit 8f871ba

Browse files
authored
Mypy passes strict check (#115)
1 parent bd512b1 commit 8f871ba

7 files changed

Lines changed: 109 additions & 44 deletions

File tree

isotp/__init__.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,38 @@
11
_major_version_ = 2
22

3+
__all__ = [
4+
'CanMessage',
5+
'AddressingMode',
6+
'TargetAddressType',
7+
'Address',
8+
'AsymmetricAddress',
9+
'TransportLayerLogic',
10+
'TransportLayer',
11+
'CanStack',
12+
'NotifierBasedCanStack',
13+
'socket',
14+
15+
'IsoTpError',
16+
'BlockingSendFailure',
17+
'BadGeneratorError',
18+
'BlockingSendTimeout',
19+
'FlowControlTimeoutError',
20+
'ConsecutiveFrameTimeoutError',
21+
'InvalidCanDataError',
22+
'UnexpectedFlowControlError',
23+
'UnexpectedConsecutiveFrameError',
24+
'ReceptionInterruptedWithSingleFrameError',
25+
'ReceptionInterruptedWithFirstFrameError',
26+
'WrongSequenceNumberError',
27+
'UnsupportedWaitFrameError',
28+
'MaximumWaitFrameReachedError',
29+
'FrameTooLongError',
30+
'ChangingInvalidRXDLError',
31+
'MissingEscapeSequenceError',
32+
'InvalidCanFdFirstFrameRXDL',
33+
'OverflowError'
34+
]
35+
336
from isotp.errors import *
437
from isotp.can_message import CanMessage
538
from isotp.address import AddressingMode, TargetAddressType, Address, AsymmetricAddress

isotp/address.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class AddressingMode(Enum):
1717
Mixed_29bits = 6
1818

1919
@classmethod
20-
def get_name(cls, num):
20+
def get_name(cls, num: Union[int, "AddressingMode"]) -> str:
2121
return cls(num).name
2222

2323

@@ -76,6 +76,10 @@ def get_tx_payload_prefix(self) -> bytes:
7676
def is_partial_address(self) -> bool:
7777
raise NotImplementedError("Abstract method")
7878

79+
@abc.abstractmethod
80+
def get_content_str(self) -> str:
81+
raise NotImplementedError("Abstract method")
82+
7983

8084
class Address(AbstractAddress):
8185
"""
@@ -203,7 +207,7 @@ def __init__(self,
203207
else:
204208
raise RuntimeError('This exception should never be raised.')
205209

206-
def not_implemented_func_with_partial(*args, **kwargs):
210+
def not_implemented_func_with_partial(*args: Any, **kwargs: Any) -> None:
207211
raise NotImplementedError("Not possible with partial address")
208212

209213
# Remove unavailable functions to be strict
@@ -222,7 +226,7 @@ def not_implemented_func_with_partial(*args, **kwargs):
222226
setattr(self, 'is_tx_29bits', not_implemented_func_with_partial)
223227
setattr(self, 'get_tx_payload_prefix', not_implemented_func_with_partial)
224228

225-
def validate(self):
229+
def validate(self) -> None:
226230
if self._rx_only and self._tx_only:
227231
raise ValueError("Address cannot be tx only and rx only")
228232

@@ -434,7 +438,7 @@ def get_content_str(self) -> str:
434438
vals_str = ', '.join(['%s:0x%02x' % (k, val_dict[k]) for k in val_dict])
435439
return '[%s - %s]' % (AddressingMode.get_name(self._addressing_mode), vals_str)
436440

437-
def __repr__(self):
441+
def __repr__(self) -> str:
438442
return '<IsoTP Address %s at 0x%08x>' % (self.get_content_str(), id(self))
439443

440444

@@ -504,5 +508,8 @@ def get_tx_payload_prefix(self) -> bytes:
504508
def is_partial_address(self) -> bool:
505509
return False
506510

511+
def get_content_str(self) -> str:
512+
return f"RxAddr: {self.rx_addr.__repr__()} - TxAddr: {self.tx_addr.__repr__()}"
513+
507514
def __repr__(self) -> str:
508-
return f'<{self.__class__.__name__} - RxAddr: {self.rx_addr.__repr__()} - TxAddr: {self.tx_addr.__repr__()}>'
515+
return f'<{self.__class__.__name__} - {self.get_content_str()}>'

isotp/errors.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,30 @@
1+
__all__ = [
2+
'IsoTpError',
3+
'BlockingSendFailure',
4+
'BadGeneratorError',
5+
'BlockingSendTimeout',
6+
'FlowControlTimeoutError',
7+
'ConsecutiveFrameTimeoutError',
8+
'InvalidCanDataError',
9+
'UnexpectedFlowControlError',
10+
'UnexpectedConsecutiveFrameError',
11+
'ReceptionInterruptedWithSingleFrameError',
12+
'ReceptionInterruptedWithFirstFrameError',
13+
'WrongSequenceNumberError',
14+
'UnsupportedWaitFrameError',
15+
'MaximumWaitFrameReachedError',
16+
'FrameTooLongError',
17+
'ChangingInvalidRXDLError',
18+
'MissingEscapeSequenceError',
19+
'InvalidCanFdFirstFrameRXDL',
20+
'OverflowError'
21+
]
22+
23+
from typing import Any
124

225

326
class IsoTpError(Exception):
4-
def __init__(self, *args, **kwargs):
27+
def __init__(self, *args: Any, **kwargs: Any) -> None:
528
Exception.__init__(self, *args, **kwargs)
629

730

isotp/protocol.py

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@
3636
_can_available = False
3737

3838

39-
def is_documented_by(original):
40-
def wrapper(target):
39+
def is_documented_by(original: Callable[[Any], Any]) -> Callable[[Any], Any]:
40+
def wrapper(target: Callable[[Any], Any]) -> Callable[[Any], Any]:
4141
target.__doc__ = original.__doc__
4242
return target
4343
return wrapper
@@ -75,7 +75,7 @@ class FlowStatus:
7575
escape_sequence: bool
7676
can_dl: int
7777

78-
def __init__(self, msg: CanMessage, start_of_data: int = 0):
78+
def __init__(self, msg: CanMessage, start_of_data: int = 0) -> None:
7979

8080
self.data = bytes()
8181
self.length = None
@@ -172,7 +172,7 @@ def __init__(self, msg: CanMessage, start_of_data: int = 0):
172172
def craft_flow_control_data(cls, flow_status: int, blocksize: int, stmin: int) -> bytes:
173173
return bytes([(0x30 | (flow_status) & 0xF), blocksize & 0xFF, stmin & 0xFF])
174174

175-
def name(self):
175+
def name(self) -> str:
176176
if self.type is None:
177177
return "[None]"
178178

@@ -200,7 +200,7 @@ class RateLimiter:
200200
bit_total: int
201201
window_bit_max: float
202202

203-
def __init__(self, mean_bitrate=None, window_size_sec=0.1):
203+
def __init__(self, mean_bitrate: float = 10000000, window_size_sec: float = 0.1) -> None:
204204
self.enabled = False
205205
self.mean_bitrate = mean_bitrate
206206
self.window_size_sec = window_size_sec
@@ -346,7 +346,7 @@ class Params:
346346
logger_name: str
347347
wait_func: Callable[[float], None]
348348

349-
def __init__(self):
349+
def __init__(self) -> None:
350350
self.stmin = 0
351351
self.blocksize = 8
352352
self.override_receiver_stmin = None
@@ -552,7 +552,7 @@ class ProcessStats:
552552
sent: int
553553
frame_received: int
554554

555-
def __repr__(self):
555+
def __repr__(self) -> str:
556556
return f'<{self.__class__.__name__} received:{self.received} (processed: {self.received_processed}, sent: {self.sent})>'
557557

558558
@dataclass(frozen=True)
@@ -689,7 +689,8 @@ def load_params(self) -> None:
689689
def send(self,
690690
data: Union[bytes, bytearray, SendGenerator],
691691
target_address_type: Optional[Union[isotp.address.TargetAddressType, int]] = None,
692-
send_timeout: Optional[float] = None):
692+
send_timeout: Optional[float] = None
693+
) -> None:
693694
"""
694695
Enqueue an IsoTP frame to be sent over CAN network.
695696
When performing a blocking send, this method returns only when the transmission is complete or raise an exception when a failure or a timeout occurs.
@@ -874,7 +875,7 @@ def process(self, rx_timeout: float = 0.0, do_rx: bool = True, do_tx: bool = Tru
874875
frame_received=nb_frame_received
875876
)
876877

877-
def _set_rxfn(self, rxfn: "TransportLayerLogic.RxFn"):
878+
def _set_rxfn(self, rxfn: "TransportLayerLogic.RxFn") -> None:
878879
"""
879880
Allow post init change of rxfn. This is a trick to implement the threaded Transport Layer
880881
and keeping the ability to run the TransportLayerLogic without threads for backward compatibility
@@ -1185,7 +1186,7 @@ def set_sleep_timing(self, idle: float, wait_fc: float) -> None:
11851186
(self.RxState.IDLE, self.TxState.WAIT_FC): wait_fc,
11861187
}
11871188

1188-
def set_address(self, address: Union[isotp.address.Address, isotp.address.AsymmetricAddress]):
1189+
def set_address(self, address: Union[isotp.address.Address, isotp.address.AsymmetricAddress]) -> None:
11891190
"""
11901191
Sets the layer address. Can be set after initialization if needed. May cause a timeout if called while a transmission is active.
11911192
@@ -1249,10 +1250,10 @@ def _start_rx_cf_timer(self) -> None:
12491250
self.timer_rx_cf = Timer(timeout=float(self.params.rx_consecutive_frame_timeout) / 1000)
12501251
self.timer_rx_cf.start()
12511252

1252-
def _append_rx_data(self, data) -> None:
1253+
def _append_rx_data(self, data: Union[bytes, bytearray]) -> None:
12531254
self.rx_buffer.extend(data)
12541255

1255-
def _request_tx_flowcontrol(self, status=PDU.FlowStatus.ContinueToSend) -> None:
1256+
def _request_tx_flowcontrol(self, status: int = PDU.FlowStatus.ContinueToSend) -> None:
12561257
self.pending_flow_control_tx = True
12571258
self.pending_flowcontrol_status = status
12581259

@@ -1302,7 +1303,7 @@ def _get_nearest_can_fd_size(self, size: int) -> int:
13021303
if size <= 64: return 64
13031304
raise ValueError("Impossible data size for CAN FD : %d " % (size))
13041305

1305-
def _make_flow_control(self, flow_status: int = PDU.FlowStatus.ContinueToSend, blocksize: Optional[int] = None, stmin: Optional[int] = None):
1306+
def _make_flow_control(self, flow_status: int = PDU.FlowStatus.ContinueToSend, blocksize: Optional[int] = None, stmin: Optional[int] = None) -> CanMessage:
13061307
if blocksize is None:
13071308
blocksize = self.params.blocksize
13081309

@@ -1347,11 +1348,11 @@ def _stop_receiving(self) -> None:
13471348
self._stop_sending_flow_control()
13481349
self.timer_rx_cf.stop()
13491350

1350-
def clear_rx_queue(self):
1351+
def clear_rx_queue(self) -> None:
13511352
while not self.rx_queue.empty():
13521353
self.rx_queue.get_nowait()
13531354

1354-
def clear_tx_queue(self):
1355+
def clear_tx_queue(self) -> None:
13551356
while not self.tx_queue.empty():
13561357
self.tx_queue.get_nowait()
13571358

@@ -1476,7 +1477,7 @@ class Events:
14761477
reset_tx: threading.Event
14771478
reset_rx: threading.Event
14781479

1479-
def __init__(self):
1480+
def __init__(self) -> None:
14801481
self.main_thread_ready = threading.Event()
14811482
self.relay_thread_ready = threading.Event()
14821483
self.stop_requested = threading.Event()
@@ -1497,7 +1498,7 @@ def __init__(self,
14971498
address: isotp.Address,
14981499
error_handler: Optional[TransportLayerLogic.ErrorHandler] = None,
14991500
params: Optional[Dict[str, Any]] = None,
1500-
read_timeout=0.05):
1501+
read_timeout: float = 0.05) -> None:
15011502

15021503
self.rx_relay_queue = queue.Queue()
15031504
self.started = False
@@ -1624,7 +1625,7 @@ def _main_thread_fn(self) -> None:
16241625
self.logger.debug("Main thread is exiting")
16251626

16261627
@is_documented_by(TransportLayerLogic.stop_sending)
1627-
def stop_sending(self):
1628+
def stop_sending(self) -> None:
16281629
if self.started:
16291630
if not self.events.stop_requested.is_set():
16301631
if self.main_thread is not None and self.main_thread.is_alive():
@@ -1635,7 +1636,7 @@ def stop_sending(self):
16351636
self._stop_sending(success=False)
16361637

16371638
@is_documented_by(TransportLayerLogic.stop_receiving)
1638-
def stop_receiving(self):
1639+
def stop_receiving(self) -> None:
16391640
if self.started:
16401641
if not self.events.stop_requested.is_set():
16411642
if self.main_thread is not None and self.main_thread.is_alive():
@@ -1653,7 +1654,7 @@ def process(self, rx_timeout: float = 0.0, do_rx: bool = True, do_tx: bool = Tru
16531654
return super().process(rx_timeout=rx_timeout, do_rx=do_rx, do_tx=do_tx)
16541655

16551656
@is_documented_by(TransportLayerLogic.reset)
1656-
def reset(self):
1657+
def reset(self) -> None:
16571658
if self.started:
16581659
raise RuntimeError("Cannot call reset() after a start(). See documentation and notes about backward compatibility.")
16591660
super().reset()
@@ -1714,7 +1715,7 @@ def _rx_canbus(self, timeout: float) -> Optional[CanMessage]:
17141715
msg = self.bus.recv(timeout)
17151716
return _python_can_to_isotp_message(msg)
17161717

1717-
def __init__(self, bus: "can.BusABC", *args, **kwargs):
1718+
def __init__(self, bus: "can.BusABC", *args: Any, **kwargs: Any):
17181719
if not _can_available:
17191720
raise RuntimeError(f"python-can is not installed in this environment and is required for the {self.__class__.__name__} object.")
17201721

@@ -1755,14 +1756,14 @@ class NotifierBasedCanStack(TransportLayer, BusOwner):
17551756
notifier: "can.Notifier"
17561757
bus: "can.BusABC"
17571758

1758-
def _rx_canbus(self, timeout: float):
1759+
def _rx_canbus(self, timeout: float) -> Optional[CanMessage]:
17591760
if self.buffered_reader is None:
17601761
return None
17611762

17621763
msg = self.buffered_reader.get_message(timeout=timeout)
17631764
return _python_can_to_isotp_message(msg)
17641765

1765-
def __init__(self, bus: "can.BusABC", notifier: "can.Notifier", *args, **kwargs):
1766+
def __init__(self, bus: "can.BusABC", notifier: "can.Notifier", *args: Any, **kwargs: Any) -> None:
17661767
if not _can_available:
17671768
raise RuntimeError(f"python-can is not installed in this environment and is required for the {self.__class__.__name__} object.")
17681769

@@ -1781,14 +1782,15 @@ def __init__(self, bus: "can.BusABC", notifier: "can.Notifier", *args, **kwargs)
17811782
))
17821783
super().__init__(*args, **kwargs)
17831784

1784-
def start(self):
1785+
def start(self) -> None:
17851786
self.buffered_reader = can.BufferedReader()
17861787
self.notifier.add_listener(self.buffered_reader)
17871788
super().start()
17881789

1789-
def stop(self):
1790+
def stop(self) -> None:
17901791
try:
1791-
self.notifier.remove_listener(self.buffered_reader)
1792+
if self.buffered_reader is not None:
1793+
self.notifier.remove_listener(self.buffered_reader)
17921794
except Exception:
17931795
pass
17941796
self.buffered_reader = None

isotp/tools.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ class Timer:
1010
start_time: Optional[int]
1111
timeout: int
1212

13-
def __init__(self, timeout: float):
13+
def __init__(self, timeout: float) -> None:
1414
self.set_timeout(timeout)
1515
self.start_time = None
1616

1717
def set_timeout(self, timeout: float) -> None:
1818
self.timeout = int(timeout * 1e9)
1919

20-
def start(self, timeout=None) -> None:
20+
def start(self, timeout: Optional[float] = None) -> None:
2121
if timeout is not None:
2222
self.set_timeout(timeout)
2323
self.start_time = time.perf_counter_ns()

isotp/tpsock/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ class socket:
8484
closed: bool
8585
_socket: socket_module.socket
8686

87-
def __init__(self, timeout=None):
87+
def __init__(self, timeout: Optional[float] = None) -> None:
8888
check_support()
8989
from . import opts # import only if required.
9090
self.interface = None
@@ -287,13 +287,13 @@ def close(self) -> None:
287287
self.closed = True
288288
self.address = None
289289

290-
def __delete__(self):
290+
def __delete__(self) -> None:
291291
if isinstance(self._socket, socket_module.socket):
292292
self._socket.close()
293-
self._socket = None
294293

295-
def __repr__(self):
294+
def __repr__(self) -> str:
296295
if self.bound:
296+
assert self.address is not None
297297
return "<ISO-TP Socket: %s, %s>" % (self.interface, self.address.get_content_str())
298298
else:
299299
status = "Closed" if self.closed else "Unbound"

0 commit comments

Comments
 (0)