From 8c6e1c67af4dda952b620ce0d4b1e38b38dab44f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frieder=20Sch=C3=BCler?= Date: Wed, 29 Apr 2026 11:10:00 +0200 Subject: [PATCH 1/3] Fix trivial mypy errors - Add mypy overrides to ignore missing imports for 'can' and 'canmatrix' - Replace List[int] with list[int] (PEP 585, supported since Python 3.9) - Add type annotations for untyped variables (var-annotated): - lss.py: Queue[bytes] - node/local.py: list[Callable] for callbacks - node/remote.py: list[SdoClient] for sdo_channels - objectdictionary/__init__.py: dict[int, ODVariable] / dict[str, ODVariable] --- canopen/lss.py | 2 +- canopen/node/local.py | 9 +++++---- canopen/node/remote.py | 2 +- canopen/objectdictionary/__init__.py | 14 +++++++------- pyproject.toml | 4 ++++ 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/canopen/lss.py b/canopen/lss.py index 7c0b92a6..311f77b5 100644 --- a/canopen/lss.py +++ b/canopen/lss.py @@ -85,7 +85,7 @@ def __init__(self) -> None: self.network: canopen.network.Network = canopen.network._UNINITIALIZED_NETWORK self._node_id = 0 self._data = None - self.responses = queue.Queue() + self.responses: queue.Queue[bytes] = queue.Queue() def send_switch_state_global(self, mode): """switch mode to CONFIGURATION_STATE or WAITING_STATE diff --git a/canopen/node/local.py b/canopen/node/local.py index 886d8ac8..cc1c3d0f 100644 --- a/canopen/node/local.py +++ b/canopen/node/local.py @@ -1,6 +1,7 @@ from __future__ import annotations import logging +from collections.abc import Callable from typing import Union import canopen.network @@ -26,8 +27,8 @@ def __init__( super(LocalNode, self).__init__(node_id, object_dictionary) self.data_store: dict[int, dict[int, bytes]] = {} - self._read_callbacks = [] - self._write_callbacks = [] + self._read_callbacks: list[Callable] = [] + self._write_callbacks: list[Callable] = [] self.sdo = SdoServer(0x600 + self.id, 0x580 + self.id, self) self.tpdo = TPDO(self) @@ -62,10 +63,10 @@ def remove_network(self) -> None: self.nmt.network = canopen.network._UNINITIALIZED_NETWORK self.emcy.network = canopen.network._UNINITIALIZED_NETWORK - def add_read_callback(self, callback): + def add_read_callback(self, callback: Callable) -> None: self._read_callbacks.append(callback) - def add_write_callback(self, callback): + def add_write_callback(self, callback: Callable) -> None: self._write_callbacks.append(callback) def get_data( diff --git a/canopen/node/remote.py b/canopen/node/remote.py index 371f784c..01bf8f82 100644 --- a/canopen/node/remote.py +++ b/canopen/node/remote.py @@ -39,7 +39,7 @@ def __init__( #: Enable WORKAROUND for reversed PDO mapping entries self.curtis_hack = False - self.sdo_channels = [] + self.sdo_channels: list[SdoClient] = [] self.sdo = self.add_sdo(0x600 + self.id, 0x580 + self.id) self.tpdo = TPDO(self) self.rpdo = RPDO(self) diff --git a/canopen/objectdictionary/__init__.py b/canopen/objectdictionary/__init__.py index fa694c56..133476e3 100644 --- a/canopen/objectdictionary/__init__.py +++ b/canopen/objectdictionary/__init__.py @@ -207,8 +207,8 @@ def __init__(self, name: str, index: int): self.name = name #: Storage location of index self.storage_location = None - self.subindices = {} - self.names = {} + self.subindices: dict[int, ODVariable] = {} + self.names: dict[str, ODVariable] = {} def __repr__(self) -> str: return f"<{type(self).__qualname__} {self.name!r} at {pretty_index(self.index)}>" @@ -266,8 +266,8 @@ def __init__(self, name: str, index: int): self.name = name #: Storage location of index self.storage_location = None - self.subindices = {} - self.names = {} + self.subindices: dict[int, ODVariable] = {} + self.names: dict[str, ODVariable] = {} def __repr__(self) -> str: return f"<{type(self).__qualname__} {self.name!r} at {pretty_index(self.index)}>" @@ -413,7 +413,7 @@ def add_value_description(self, value: int, descr: str) -> None: """ self.value_descriptions[value] = descr - def add_bit_definition(self, name: str, bits: List[int]) -> None: + def add_bit_definition(self, name: str, bits: list[int]) -> None: """Associate bit(s) with a string description. :param name: Name of bit(s) @@ -508,7 +508,7 @@ def encode_desc(self, desc: str) -> int: raise ValueError( f"No value corresponds to '{desc}'. Valid values are: {valid_values}") - def decode_bits(self, value: int, bits: List[int]) -> int: + def decode_bits(self, value: int, bits: list[int]) -> int: try: bits = self.bit_definitions[bits] except (TypeError, KeyError): @@ -518,7 +518,7 @@ def decode_bits(self, value: int, bits: List[int]) -> int: mask |= 1 << bit return (value & mask) >> min(bits) - def encode_bits(self, original_value: int, bits: List[int], bit_value: int): + def encode_bits(self, original_value: int, bits: list[int], bit_value: int): try: bits = self.bit_definitions[bits] except (TypeError, KeyError): diff --git a/pyproject.toml b/pyproject.toml index e24f6132..73f9914f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,3 +56,7 @@ exclude = [ "^test*", "^setup.py*", ] + +[[tool.mypy.overrides]] +module = ["canmatrix.*"] +ignore_missing_imports = true From 34a3cc900aaa83a7b2ade1cd580bd28bac4cece7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Tue, 5 May 2026 21:09:28 +0200 Subject: [PATCH 2/3] remove None return annotations --- canopen/node/local.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/canopen/node/local.py b/canopen/node/local.py index cc1c3d0f..3620152c 100644 --- a/canopen/node/local.py +++ b/canopen/node/local.py @@ -63,10 +63,10 @@ def remove_network(self) -> None: self.nmt.network = canopen.network._UNINITIALIZED_NETWORK self.emcy.network = canopen.network._UNINITIALIZED_NETWORK - def add_read_callback(self, callback: Callable) -> None: + def add_read_callback(self, callback: Callable): self._read_callbacks.append(callback) - def add_write_callback(self, callback: Callable) -> None: + def add_write_callback(self, callback: Callable): self._write_callbacks.append(callback) def get_data( From e9d6d4b5a67d654b22ecf7fd9a0a912de87dc902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Tue, 5 May 2026 21:09:50 +0200 Subject: [PATCH 3/3] Move typing ignore config to where canmatrix is used. This should have the advantage of affecting various type checkers, not only mypy. When the upstream canmatrix package does support type hints (work is underway), this place is likely to get noticed and the comment removed. --- canopen/pdo/base.py | 2 +- pyproject.toml | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/canopen/pdo/base.py b/canopen/pdo/base.py index 96ad057a..f9973882 100644 --- a/canopen/pdo/base.py +++ b/canopen/pdo/base.py @@ -98,7 +98,7 @@ def export(self, filename): :rtype: canmatrix.canmatrix.CanMatrix """ try: - from canmatrix import canmatrix + from canmatrix import canmatrix # type:ignore # (typing still in progress) from canmatrix import formats except ImportError: raise NotImplementedError("This feature requires the 'canopen[db_export]' feature") diff --git a/pyproject.toml b/pyproject.toml index 73f9914f..e24f6132 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,7 +56,3 @@ exclude = [ "^test*", "^setup.py*", ] - -[[tool.mypy.overrides]] -module = ["canmatrix.*"] -ignore_missing_imports = true