hardbyte / python-can

The can package provides controller area network support for Python developers
https://python-can.readthedocs.io
GNU Lesser General Public License v3.0
1.29k stars 597 forks source link

Add mypy checker #598

Closed felixdivo closed 4 years ago

felixdivo commented 5 years ago

Add support for static typing: http://mypy-lang.org/

felixdivo commented 5 years ago

As part of this, we should convert the scarcely existing comment-based typing annotations to the newer syntax. I remember it being present at least in can/viewer.py.

felixdivo commented 5 years ago

Adding the checker does not mean that all classes have to annotated, it only means that the checks are run on what is there (which might be pretty much nothing at the beginning).

karlding commented 5 years ago

It might also make sense to get typing information for docs from the typing annotations instead of duplicating work by annotating both the docstring and providing the typing annotation?

I believe sphinx-autodoc-typehints should be able to handle this.

karlding commented 5 years ago

So I took a first stab at adding this, but it seems like running mypy with no changes currently fails with a bunch of errors for interfaces that only have Windows implementations.

$ mypy can/
can/ctypesutil.py:16: error: Module has no attribute "WinDLL"
can/ctypesutil.py:61: error: Invalid base class
can/interfaces/usb2can/serial_selector.py:9: error: Cannot find module named 'win32com.client'
can/interfaces/usb2can/serial_selector.py:9: error: Cannot find module named 'win32com'
can/bus.py:11: error: Cannot find module named 'aenum'
can/interfaces/systec/structures.py:15: error: Module 'ctypes' has no attribute 'WINFUNCTYPE'
can/listener.py:11: error: Module 'queue' has no attribute 'SimpleQueue'
can/thread_safe_bus.py:8: error: Cannot find module named 'wrapt'
can/thread_safe_bus.py:19: error: Incompatible import of "nullcontext" (imported name has type overloaded function, local name has type "Type[nullcontext]")
can/thread_safe_bus.py:23: error: Name 'nullcontext' already defined (possibly by an import)
can/__init__.py:13: error: Need type annotation for 'rc'
can/viewer.py:45: error: Incompatible types in assignment (expression has type "None", variable has type Module)
can/viewer.py:164: error: Name 'struct_t' already defined on line 155
can/interfaces/virtual.py:25: error: Need type annotation for 'channels'
can/interfaces/slcan.py:20: error: Cannot find module named 'serial'
can/interfaces/iscan.py:37: error: Incompatible types in assignment (expression has type "None", variable has type "CDLL")
can/interfaces/iscan.py:41: error: Cannot assign to a method
can/interfaces/iscan.py:41: error: Invalid self argument "_FuncPointer" to attribute function "errcheck" with type "Callable[[Optional[Type[_CData]], _FuncPointer, Tuple[_CData, ...]], _CData]"
can/interfaces/iscan.py:41: error: Incompatible types in assignment (expression has type "Callable[[Any, Any, Any], Any]", variable has type "Callable[[_FuncPointer, Tuple[_CData, ...]], _CData]")
can/interfaces/iscan.py:43: error: Cannot assign to a method
can/interfaces/iscan.py:43: error: Invalid self argument "_FuncPointer" to attribute function "errcheck" with type "Callable[[Optional[Type[_CData]], _FuncPointer, Tuple[_CData, ...]], _CData]"
can/interfaces/iscan.py:43: error: Incompatible types in assignment (expression has type "Callable[[Any, Any, Any], Any]", variable has type "Callable[[_FuncPointer, Tuple[_CData, ...]], _CData]")
can/interfaces/iscan.py:45: error: Cannot assign to a method
can/interfaces/iscan.py:45: error: Invalid self argument "_FuncPointer" to attribute function "errcheck" with type "Callable[[Optional[Type[_CData]], _FuncPointer, Tuple[_CData, ...]], _CData]"
can/interfaces/iscan.py:45: error: Incompatible types in assignment (expression has type "Callable[[Any, Any, Any], Any]", variable has type "Callable[[_FuncPointer, Tuple[_CData, ...]], _CData]")
can/interfaces/iscan.py:47: error: Cannot assign to a method
can/interfaces/iscan.py:47: error: Invalid self argument "_FuncPointer" to attribute function "errcheck" with type "Callable[[Optional[Type[_CData]], _FuncPointer, Tuple[_CData, ...]], _CData]"
can/interfaces/iscan.py:47: error: Incompatible types in assignment (expression has type "Callable[[Any, Any, Any], Any]", variable has type "Callable[[_FuncPointer, Tuple[_CData, ...]], _CData]")
can/interfaces/canalystii.py:65: error: Name 'WinDLL' is not defined
can/interfaces/serial/serial_can.py:18: error: Cannot find module named 'serial'
can/interfaces/pcan/pcan.py:17: error: Cannot find module named 'uptime'
can/interfaces/pcan/pcan.py:28: error: Cannot find module named '_overlapped'
can/interfaces/pcan/pcan.py:35: error: Cannot find module named 'win32event'
can/interfaces/pcan/pcan.py:36: error: Name 'WaitForSingleObject' already defined on line 82
can/interfaces/pcan/pcan.py:36: error: Name 'WAIT_OBJECT_0' already defined on line 44
can/interfaces/pcan/pcan.py:36: error: Name 'INFINITE' already defined on line 24
can/interfaces/kvaser/canlib.py:37: error: Incompatible types in assignment (expression has type "None", variable has type "CDLL")
can/interfaces/ics_neovi/neovi_bus.py:21: error: Cannot find module named 'ics'
can/interfaces/ics_neovi/neovi_bus.py:21: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports
can/interfaces/vector/vxlapi.py:24: error: Module has no attribute "windll"
can/interfaces/systec/ucan.py:118: error: Module 'ctypes' has no attribute 'WinDLL'
can/interfaces/systec/ucan.py:324: error: Need type annotation for '_modules_found'
can/interfaces/systec/ucan.py:1162: error: "Type[UcanServer]" has no attribute "_enum_callback_ref"
can/interfaces/ixxat/canlib.py:26: error: Module 'can.ctypesutil' has no attribute 'HRESULT'
can/interfaces/ixxat/canlib.py:140: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:143: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:150: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:152: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:154: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:162: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:166: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:169: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:176: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:183: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:187: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:189: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:196: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:203: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:210: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:217: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:224: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:232: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:239: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:246: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:248: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:250: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:254: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:261: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:268: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:275: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:282: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:289: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:296: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:298: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:305: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:309: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:316: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:323: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:330: error: "None" has no attribute "map_symbol"
can/interfaces/ixxat/canlib.py:336: error: "None" has no attribute "vciInitialize"
can/interfaces/vector/canlib.py:23: error: Cannot find module named 'win32event'
can/interfaces/vector/canlib.py:23: error: Name 'WaitForSingleObject' already defined on line 82
can/interfaces/vector/canlib.py:23: error: Name 'INFINITE' already defined on line 24
can/interfaces/vector/canlib.py:43: error: Incompatible import of "vxlapi" (imported name has type Module, local name has type "object")
The command "mypy can/" exited with 1.

Does it make sense to refactor certain imports to only run on Windows, and then run mypy --platform win32 instead on those?

felixdivo commented 5 years ago

651 Added mymy checking in the CI pipeline

654 Added sphinx-autodoc-typehints to sphinx docs

felixdivo commented 5 years ago

Large parts of can/*.py and some first files in can/io/*.py are now type checked.