Skip to content

Commit 00e2302

Browse files
authored
Merge pull request #1229 from zariiii9003/vector_mypy
Enable mypy for vector interface
2 parents d142257 + 50071cc commit 00e2302

File tree

4 files changed

+110
-61
lines changed

4 files changed

+110
-61
lines changed

can/interfaces/vector/canlib.py

+75-55
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,29 @@
1010
import logging
1111
import time
1212
import os
13-
from typing import List, NamedTuple, Optional, Tuple, Sequence, Union
13+
from types import ModuleType
14+
from typing import (
15+
List,
16+
NamedTuple,
17+
Optional,
18+
Tuple,
19+
Sequence,
20+
Union,
21+
Any,
22+
Dict,
23+
Callable,
24+
)
1425

26+
WaitForSingleObject: Optional[Callable[[int, int], int]]
27+
INFINITE: Optional[int]
1528
try:
1629
# Try builtin Python 3 Windows API
1730
from _winapi import WaitForSingleObject, INFINITE
1831

1932
HAS_EVENTS = True
2033
except ImportError:
21-
try:
22-
# Try pywin32 package
23-
from win32event import WaitForSingleObject, INFINITE
24-
25-
HAS_EVENTS = True
26-
except ImportError:
27-
# Use polling instead
28-
HAS_EVENTS = False
34+
WaitForSingleObject, INFINITE = None, None
35+
HAS_EVENTS = False
2936

3037
# Import Modules
3138
# ==============
@@ -36,7 +43,7 @@
3643
deprecated_args_alias,
3744
time_perfcounter_correlation,
3845
)
39-
from can.typechecking import AutoDetectedConfig, CanFilters
46+
from can.typechecking import AutoDetectedConfig, CanFilters, Channel
4047

4148
# Define Module Logger
4249
# ====================
@@ -48,7 +55,7 @@
4855
from . import xldefine, xlclass
4956

5057
# Import safely Vector API module for Travis tests
51-
xldriver = None
58+
xldriver: Optional[ModuleType] = None
5259
try:
5360
from . import xldriver
5461
except Exception as exc:
@@ -74,19 +81,19 @@ def __init__(
7481
can_filters: Optional[CanFilters] = None,
7582
poll_interval: float = 0.01,
7683
receive_own_messages: bool = False,
77-
bitrate: int = None,
84+
bitrate: Optional[int] = None,
7885
rx_queue_size: int = 2 ** 14,
79-
app_name: str = "CANalyzer",
80-
serial: int = None,
86+
app_name: Optional[str] = "CANalyzer",
87+
serial: Optional[int] = None,
8188
fd: bool = False,
82-
data_bitrate: int = None,
89+
data_bitrate: Optional[int] = None,
8390
sjw_abr: int = 2,
8491
tseg1_abr: int = 6,
8592
tseg2_abr: int = 3,
8693
sjw_dbr: int = 2,
8794
tseg1_dbr: int = 6,
8895
tseg2_dbr: int = 3,
89-
**kwargs,
96+
**kwargs: Any,
9097
) -> None:
9198
"""
9299
:param channel:
@@ -144,16 +151,18 @@ def __init__(
144151

145152
if xldriver is None:
146153
raise CanInterfaceNotImplementedError("The Vector API has not been loaded")
154+
self.xldriver = xldriver # keep reference so mypy knows it is not None
147155

148156
self.poll_interval = poll_interval
149157

150-
if isinstance(channel, str): # must be checked before generic Sequence
158+
self.channels: Sequence[int]
159+
if isinstance(channel, int):
160+
self.channels = [channel]
161+
elif isinstance(channel, str): # must be checked before generic Sequence
151162
# Assume comma separated string of channels
152163
self.channels = [int(ch.strip()) for ch in channel.split(",")]
153-
elif isinstance(channel, int):
154-
self.channels = [channel]
155164
elif isinstance(channel, Sequence):
156-
self.channels = channel
165+
self.channels = [int(ch) for ch in channel]
157166
else:
158167
raise TypeError(
159168
f"Invalid type for channels parameter: {type(channel).__name__}"
@@ -185,12 +194,12 @@ def __init__(
185194
"None of the configured channels could be found on the specified hardware."
186195
)
187196

188-
xldriver.xlOpenDriver()
197+
self.xldriver.xlOpenDriver()
189198
self.port_handle = xlclass.XLportHandle(xldefine.XL_INVALID_PORTHANDLE)
190199
self.mask = 0
191200
self.fd = fd
192201
# Get channels masks
193-
self.channel_masks = {}
202+
self.channel_masks: Dict[Optional[Channel], int] = {}
194203
self.index_to_channel = {}
195204

196205
for channel in self.channels:
@@ -200,7 +209,7 @@ def __init__(
200209
app_name, channel
201210
)
202211
LOG.debug("Channel index %d found", channel)
203-
idx = xldriver.xlGetChannelIndex(hw_type, hw_index, hw_channel)
212+
idx = self.xldriver.xlGetChannelIndex(hw_type, hw_index, hw_channel)
204213
if idx < 0:
205214
# Undocumented behavior! See issue #353.
206215
# If hardware is unavailable, this function returns -1.
@@ -224,7 +233,7 @@ def __init__(
224233
if bitrate or fd:
225234
permission_mask.value = self.mask
226235
if fd:
227-
xldriver.xlOpenPort(
236+
self.xldriver.xlOpenPort(
228237
self.port_handle,
229238
self._app_name,
230239
self.mask,
@@ -234,7 +243,7 @@ def __init__(
234243
xldefine.XL_BusTypes.XL_BUS_TYPE_CAN,
235244
)
236245
else:
237-
xldriver.xlOpenPort(
246+
self.xldriver.xlOpenPort(
238247
self.port_handle,
239248
self._app_name,
240249
self.mask,
@@ -267,7 +276,7 @@ def __init__(
267276
self.canFdConf.tseg1Dbr = int(tseg1_dbr)
268277
self.canFdConf.tseg2Dbr = int(tseg2_dbr)
269278

270-
xldriver.xlCanFdSetConfiguration(
279+
self.xldriver.xlCanFdSetConfiguration(
271280
self.port_handle, self.mask, self.canFdConf
272281
)
273282
LOG.info(
@@ -289,7 +298,7 @@ def __init__(
289298
)
290299
else:
291300
if bitrate:
292-
xldriver.xlCanSetChannelBitrate(
301+
self.xldriver.xlCanSetChannelBitrate(
293302
self.port_handle, permission_mask, bitrate
294303
)
295304
LOG.info("SetChannelBitrate: baudr.=%u", bitrate)
@@ -298,16 +307,16 @@ def __init__(
298307

299308
# Enable/disable TX receipts
300309
tx_receipts = 1 if receive_own_messages else 0
301-
xldriver.xlCanSetChannelMode(self.port_handle, self.mask, tx_receipts, 0)
310+
self.xldriver.xlCanSetChannelMode(self.port_handle, self.mask, tx_receipts, 0)
302311

303312
if HAS_EVENTS:
304313
self.event_handle = xlclass.XLhandle()
305-
xldriver.xlSetNotification(self.port_handle, self.event_handle, 1)
314+
self.xldriver.xlSetNotification(self.port_handle, self.event_handle, 1)
306315
else:
307316
LOG.info("Install pywin32 to avoid polling")
308317

309318
try:
310-
xldriver.xlActivateChannel(
319+
self.xldriver.xlActivateChannel(
311320
self.port_handle, self.mask, xldefine.XL_BusTypes.XL_BUS_TYPE_CAN, 0
312321
)
313322
except VectorOperationError as error:
@@ -320,17 +329,17 @@ def __init__(
320329
if time.get_clock_info("time").resolution > 1e-5:
321330
ts, perfcounter = time_perfcounter_correlation()
322331
try:
323-
xldriver.xlGetSyncTime(self.port_handle, offset)
332+
self.xldriver.xlGetSyncTime(self.port_handle, offset)
324333
except VectorInitializationError:
325-
xldriver.xlGetChannelTime(self.port_handle, self.mask, offset)
334+
self.xldriver.xlGetChannelTime(self.port_handle, self.mask, offset)
326335
current_perfcounter = time.perf_counter()
327336
now = ts + (current_perfcounter - perfcounter)
328337
self._time_offset = now - offset.value * 1e-9
329338
else:
330339
try:
331-
xldriver.xlGetSyncTime(self.port_handle, offset)
340+
self.xldriver.xlGetSyncTime(self.port_handle, offset)
332341
except VectorInitializationError:
333-
xldriver.xlGetChannelTime(self.port_handle, self.mask, offset)
342+
self.xldriver.xlGetChannelTime(self.port_handle, self.mask, offset)
334343
self._time_offset = time.time() - offset.value * 1e-9
335344

336345
except VectorInitializationError:
@@ -339,7 +348,7 @@ def __init__(
339348
self._is_filtered = False
340349
super().__init__(channel=channel, can_filters=can_filters, **kwargs)
341350

342-
def _apply_filters(self, filters) -> None:
351+
def _apply_filters(self, filters: Optional[CanFilters]) -> None:
343352
if filters:
344353
# Only up to one filter per ID type allowed
345354
if len(filters) == 1 or (
@@ -348,7 +357,7 @@ def _apply_filters(self, filters) -> None:
348357
):
349358
try:
350359
for can_filter in filters:
351-
xldriver.xlCanSetChannelAcceptance(
360+
self.xldriver.xlCanSetChannelAcceptance(
352361
self.port_handle,
353362
self.mask,
354363
can_filter["can_id"],
@@ -370,14 +379,14 @@ def _apply_filters(self, filters) -> None:
370379
# fallback: reset filters
371380
self._is_filtered = False
372381
try:
373-
xldriver.xlCanSetChannelAcceptance(
382+
self.xldriver.xlCanSetChannelAcceptance(
374383
self.port_handle,
375384
self.mask,
376385
0x0,
377386
0x0,
378387
xldefine.XL_AcceptanceFilter.XL_CAN_EXT,
379388
)
380-
xldriver.xlCanSetChannelAcceptance(
389+
self.xldriver.xlCanSetChannelAcceptance(
381390
self.port_handle,
382391
self.mask,
383392
0x0,
@@ -417,14 +426,14 @@ def _recv_internal(
417426
else:
418427
time_left = end_time - time.time()
419428
time_left_ms = max(0, int(time_left * 1000))
420-
WaitForSingleObject(self.event_handle.value, time_left_ms)
429+
WaitForSingleObject(self.event_handle.value, time_left_ms) # type: ignore
421430
else:
422431
# Wait a short time until we try again
423432
time.sleep(self.poll_interval)
424433

425434
def _recv_canfd(self) -> Optional[Message]:
426435
xl_can_rx_event = xlclass.XLcanRxEvent()
427-
xldriver.xlCanReceive(self.port_handle, xl_can_rx_event)
436+
self.xldriver.xlCanReceive(self.port_handle, xl_can_rx_event)
428437

429438
if xl_can_rx_event.tag == xldefine.XL_CANFD_RX_EventTags.XL_CAN_EV_TAG_RX_OK:
430439
is_rx = True
@@ -470,7 +479,7 @@ def _recv_canfd(self) -> Optional[Message]:
470479
def _recv_can(self) -> Optional[Message]:
471480
xl_event = xlclass.XLevent()
472481
event_count = ctypes.c_uint(1)
473-
xldriver.xlReceive(self.port_handle, event_count, xl_event)
482+
self.xldriver.xlReceive(self.port_handle, event_count, xl_event)
474483

475484
if xl_event.tag != xldefine.XL_EventTags.XL_RECEIVE_MSG:
476485
self.handle_can_event(xl_event)
@@ -523,7 +532,7 @@ def handle_canfd_event(self, event: xlclass.XLcanRxEvent) -> None:
523532
`XL_CAN_EV_TAG_TX_ERROR`, `XL_TIMER` or `XL_CAN_EV_TAG_CHIP_STATE` tag.
524533
"""
525534

526-
def send(self, msg: Message, timeout: Optional[float] = None):
535+
def send(self, msg: Message, timeout: Optional[float] = None) -> None:
527536
self._send_sequence([msg])
528537

529538
def _send_sequence(self, msgs: Sequence[Message]) -> int:
@@ -548,7 +557,9 @@ def _send_can_msg_sequence(self, msgs: Sequence[Message]) -> int:
548557
*map(self._build_xl_event, msgs)
549558
)
550559

551-
xldriver.xlCanTransmit(self.port_handle, mask, message_count, xl_event_array)
560+
self.xldriver.xlCanTransmit(
561+
self.port_handle, mask, message_count, xl_event_array
562+
)
552563
return message_count.value
553564

554565
@staticmethod
@@ -580,7 +591,7 @@ def _send_can_fd_msg_sequence(self, msgs: Sequence[Message]) -> int:
580591
)
581592

582593
msg_count_sent = ctypes.c_uint(0)
583-
xldriver.xlCanTransmitEx(
594+
self.xldriver.xlCanTransmitEx(
584595
self.port_handle, mask, message_count, msg_count_sent, xl_can_tx_event_array
585596
)
586597
return msg_count_sent.value
@@ -611,17 +622,17 @@ def _build_xl_can_tx_event(msg: Message) -> xlclass.XLcanTxEvent:
611622
return xl_can_tx_event
612623

613624
def flush_tx_buffer(self) -> None:
614-
xldriver.xlCanFlushTransmitQueue(self.port_handle, self.mask)
625+
self.xldriver.xlCanFlushTransmitQueue(self.port_handle, self.mask)
615626

616627
def shutdown(self) -> None:
617628
super().shutdown()
618-
xldriver.xlDeactivateChannel(self.port_handle, self.mask)
619-
xldriver.xlClosePort(self.port_handle)
620-
xldriver.xlCloseDriver()
629+
self.xldriver.xlDeactivateChannel(self.port_handle, self.mask)
630+
self.xldriver.xlClosePort(self.port_handle)
631+
self.xldriver.xlCloseDriver()
621632

622633
def reset(self) -> None:
623-
xldriver.xlDeactivateChannel(self.port_handle, self.mask)
624-
xldriver.xlActivateChannel(
634+
self.xldriver.xlDeactivateChannel(self.port_handle, self.mask)
635+
self.xldriver.xlActivateChannel(
625636
self.port_handle, self.mask, xldefine.XL_BusTypes.XL_BUS_TYPE_CAN, 0
626637
)
627638

@@ -657,7 +668,7 @@ def _detect_available_configs() -> List[AutoDetectedConfig]:
657668
"vector_channel_config": channel_config,
658669
}
659670
)
660-
return configs
671+
return configs # type: ignore
661672

662673
@staticmethod
663674
def popup_vector_hw_configuration(wait_for_finish: int = 0) -> None:
@@ -666,6 +677,9 @@ def popup_vector_hw_configuration(wait_for_finish: int = 0) -> None:
666677
:param wait_for_finish:
667678
Time to wait for user input in milliseconds.
668679
"""
680+
if xldriver is None:
681+
raise CanInterfaceNotImplementedError("The Vector API has not been loaded")
682+
669683
xldriver.xlPopupHwConfig(ctypes.c_char_p(), ctypes.c_uint(wait_for_finish))
670684

671685
@staticmethod
@@ -685,14 +699,17 @@ def get_application_config(
685699
:raises can.interfaces.vector.VectorInitializationError:
686700
If the application name does not exist in the Vector hardware configuration.
687701
"""
702+
if xldriver is None:
703+
raise CanInterfaceNotImplementedError("The Vector API has not been loaded")
704+
688705
hw_type = ctypes.c_uint()
689706
hw_index = ctypes.c_uint()
690707
hw_channel = ctypes.c_uint()
691-
app_channel = ctypes.c_uint(app_channel)
708+
_app_channel = ctypes.c_uint(app_channel)
692709

693710
xldriver.xlGetApplConfig(
694711
app_name.encode(),
695-
app_channel,
712+
_app_channel,
696713
hw_type,
697714
hw_index,
698715
hw_channel,
@@ -707,7 +724,7 @@ def set_application_config(
707724
hw_type: xldefine.XL_HardwareType,
708725
hw_index: int,
709726
hw_channel: int,
710-
**kwargs,
727+
**kwargs: Any,
711728
) -> None:
712729
"""Modify the application settings in Vector Hardware Configuration.
713730
@@ -737,6 +754,9 @@ def set_application_config(
737754
:raises can.interfaces.vector.VectorInitializationError:
738755
If the application name does not exist in the Vector hardware configuration.
739756
"""
757+
if xldriver is None:
758+
raise CanInterfaceNotImplementedError("The Vector API has not been loaded")
759+
740760
xldriver.xlSetApplConfig(
741761
app_name.encode(),
742762
app_channel,
@@ -758,7 +778,7 @@ def set_timer_rate(self, timer_rate_ms: int) -> None:
758778
the timer events.
759779
"""
760780
timer_rate_10us = timer_rate_ms * 100
761-
xldriver.xlSetTimerRate(self.port_handle, timer_rate_10us)
781+
self.xldriver.xlSetTimerRate(self.port_handle, timer_rate_10us)
762782

763783

764784
class VectorChannelConfig(NamedTuple):

can/interfaces/vector/xldriver.py

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# type: ignore
12
"""
23
Ctypes wrapper module for Vector CAN Interface on win32/win64 systems.
34

0 commit comments

Comments
 (0)