From 26d394ac4708580e298eba3a305596e0393449cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Tue, 15 Jul 2025 10:15:31 +0200 Subject: [PATCH 1/9] Refactor. --- canopen/pdo/base.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/canopen/pdo/base.py b/canopen/pdo/base.py index 7bef6e62..58d5d3b7 100644 --- a/canopen/pdo/base.py +++ b/canopen/pdo/base.py @@ -40,17 +40,19 @@ def __iter__(self): return iter(self.map) def __getitem__(self, key): - if isinstance(key, int) and (0x1A00 <= key <= 0x1BFF or # By TPDO ID (512) - 0x1600 <= key <= 0x17FF or # By RPDO ID (512) - 0 < key <= 512): # By PDO Index - return self.map[key] - else: - for pdo_map in self.map.values(): - try: - return pdo_map[key] - except KeyError: - # ignore if one specific PDO does not have the key and try the next one - continue + if isinstance(key, int): + if ( + 0 < key <= 512 # By PDO Index + or 0x1600 <= key <= 0x17FF # By RPDO ID (512) + or 0x1A00 <= key <= 0x1BFF # By TPDO ID (512) + ): + return self.map[key] + for pdo_map in self.map.values(): + try: + return pdo_map[key] + except KeyError: + # ignore if one specific PDO does not have the key and try the next one + continue raise KeyError(f"PDO: {key} was not found in any map") def __len__(self): From f2263daf19f60de78872dceb7c9f3b87661b0420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Tue, 15 Jul 2025 10:15:38 +0200 Subject: [PATCH 2/9] Raise KeyError for zero index. --- canopen/pdo/base.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/canopen/pdo/base.py b/canopen/pdo/base.py index 58d5d3b7..79ff2cf8 100644 --- a/canopen/pdo/base.py +++ b/canopen/pdo/base.py @@ -41,6 +41,8 @@ def __iter__(self): def __getitem__(self, key): if isinstance(key, int): + if key == 0: + raise KeyError("PDO index zero requested for 1-based sequence") if ( 0 < key <= 512 # By PDO Index or 0x1600 <= key <= 0x17FF # By RPDO ID (512) From 0c7606f1656749aec6fec521b2e9c1e0671b43ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Tue, 15 Jul 2025 10:16:02 +0200 Subject: [PATCH 3/9] Add annotation. --- canopen/pdo/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/canopen/pdo/base.py b/canopen/pdo/base.py index 79ff2cf8..c4104143 100644 --- a/canopen/pdo/base.py +++ b/canopen/pdo/base.py @@ -39,7 +39,7 @@ def __init__(self, node: Union[LocalNode, RemoteNode]): def __iter__(self): return iter(self.map) - def __getitem__(self, key): + def __getitem__(self, key: Union[int, str]): if isinstance(key, int): if key == 0: raise KeyError("PDO index zero requested for 1-based sequence") From 7ab54ec9fd986e6644640cd41fb84bfd018bf855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Tue, 19 Aug 2025 11:56:02 +0200 Subject: [PATCH 4/9] Properly test different access type return values. Augment test_pdo_getitem() to not only check the mapped object values. What's more important is the type of object returned, and whether it is the correct object (identical to other access method results). --- test/test_pdo.py | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/test/test_pdo.py b/test/test_pdo.py index b8bb0599..822abb08 100644 --- a/test/test_pdo.py +++ b/test/test_pdo.py @@ -50,15 +50,25 @@ def test_pdo_getitem(self): self.assertEqual(node.tpdo[1]['BOOLEAN value 2'].raw, True) # Test different types of access - self.assertEqual(node.pdo[0x1600]['INTEGER16 value'].raw, -3) - self.assertEqual(node.pdo['INTEGER16 value'].raw, -3) - self.assertEqual(node.pdo.tx[1]['INTEGER16 value'].raw, -3) - self.assertEqual(node.pdo[0x2001].raw, -3) - self.assertEqual(node.tpdo[0x2001].raw, -3) - self.assertEqual(node.pdo[0x2002].raw, 0xf) - self.assertEqual(node.pdo['0x2002'].raw, 0xf) - self.assertEqual(node.tpdo[0x2002].raw, 0xf) - self.assertEqual(node.pdo[0x1600][0x2002].raw, 0xf) + by_mapping_record = node.pdo[0x1600] + self.assertIsInstance(by_mapping_record, canopen.pdo.PdoMap) + self.assertEqual(by_mapping_record['INTEGER16 value'].raw, -3) + by_object_name = node.pdo['INTEGER16 value'] + self.assertIsInstance(by_object_name, canopen.pdo.PdoVariable) + self.assertIs(by_object_name.od, node.object_dictionary['INTEGER16 value']) + self.assertEqual(by_object_name.raw, -3) + by_pdo_index = node.pdo.tx[1] + self.assertIs(by_pdo_index, by_mapping_record) + by_object_index = node.pdo[0x2001] + self.assertIsInstance(by_object_index, canopen.pdo.PdoVariable) + self.assertIs(by_object_index, by_object_name) + by_object_index_tpdo = node.tpdo[0x2001] + self.assertIs(by_object_index_tpdo, by_object_name) + by_object_index = node.pdo[0x2002] + self.assertEqual(by_object_index.raw, 0xf) + self.assertIs(node.pdo['0x2002'], by_object_index) + self.assertIs(node.tpdo[0x2002], by_object_index) + self.assertIs(node.pdo[0x1600][0x2002], by_object_index) def test_pdo_save(self): self.node.tpdo.save() From c27eeb4f8460f853f9eaf5bb621de1d76c608335 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Tue, 19 Aug 2025 12:58:57 +0200 Subject: [PATCH 5/9] Extend tests to cover KeyError exceptions. --- test/test_pdo.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test_pdo.py b/test/test_pdo.py index 822abb08..ed4e12de 100644 --- a/test/test_pdo.py +++ b/test/test_pdo.py @@ -70,6 +70,10 @@ def test_pdo_getitem(self): self.assertIs(node.tpdo[0x2002], by_object_index) self.assertIs(node.pdo[0x1600][0x2002], by_object_index) + self.assertRaises(KeyError, lambda: node.pdo[0]) + self.assertRaises(KeyError, lambda: node.tpdo[0]) + self.assertRaises(KeyError, lambda: node.pdo['DOES NOT EXIST']) + def test_pdo_save(self): self.node.tpdo.save() self.node.rpdo.save() From 9fd1dbd08e4dd9df3fed8781cebb05c0ca53a2c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Tue, 19 Aug 2025 13:03:58 +0200 Subject: [PATCH 6/9] Extend tests to cover iteration over PdoMaps. --- test/test_pdo.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/test_pdo.py b/test/test_pdo.py index ed4e12de..92671f7c 100644 --- a/test/test_pdo.py +++ b/test/test_pdo.py @@ -74,6 +74,12 @@ def test_pdo_getitem(self): self.assertRaises(KeyError, lambda: node.tpdo[0]) self.assertRaises(KeyError, lambda: node.pdo['DOES NOT EXIST']) + def test_pdo_maps_iterate(self): + node = self.node + self.assertEqual(len(node.pdo), sum(1 for _ in node.pdo)) + self.assertEqual(len(node.tpdo), sum(1 for _ in node.tpdo)) + self.assertEqual(len(node.rpdo), sum(1 for _ in node.rpdo)) + def test_pdo_save(self): self.node.tpdo.save() self.node.rpdo.save() From c611e2a65ed947745054917a3691567230c11a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Tue, 19 Aug 2025 13:07:11 +0200 Subject: [PATCH 7/9] Extend tests to cover iteration over PdoMap. --- test/test_pdo.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test_pdo.py b/test/test_pdo.py index 92671f7c..c01d4641 100644 --- a/test/test_pdo.py +++ b/test/test_pdo.py @@ -80,6 +80,9 @@ def test_pdo_maps_iterate(self): self.assertEqual(len(node.tpdo), sum(1 for _ in node.tpdo)) self.assertEqual(len(node.rpdo), sum(1 for _ in node.rpdo)) + pdo = node.tpdo[1] + self.assertEqual(len(pdo), sum(1 for _ in pdo)) + def test_pdo_save(self): self.node.tpdo.save() self.node.rpdo.save() From 19439cae704437f40d33840aa61a4ecd54d29adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Thu, 4 Sep 2025 22:53:45 +0200 Subject: [PATCH 8/9] Test whether generic PDO object summarizes TPDO and RPDO count. --- test/test_pdo.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_pdo.py b/test/test_pdo.py index c01d4641..877c081d 100644 --- a/test/test_pdo.py +++ b/test/test_pdo.py @@ -79,6 +79,7 @@ def test_pdo_maps_iterate(self): self.assertEqual(len(node.pdo), sum(1 for _ in node.pdo)) self.assertEqual(len(node.tpdo), sum(1 for _ in node.tpdo)) self.assertEqual(len(node.rpdo), sum(1 for _ in node.rpdo)) + self.assertEqual(len(node.rpdo) + len(node.tpdo), len(node.pdo)) pdo = node.tpdo[1] self.assertEqual(len(pdo), sum(1 for _ in pdo)) From 2c4450e2bd9a081135675c483cb367eacc2203f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Thu, 4 Sep 2025 23:57:24 +0200 Subject: [PATCH 9/9] Test with non-existent TPDO index. --- test/test_pdo.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test_pdo.py b/test/test_pdo.py index 877c081d..9eb6fb2f 100644 --- a/test/test_pdo.py +++ b/test/test_pdo.py @@ -73,6 +73,8 @@ def test_pdo_getitem(self): self.assertRaises(KeyError, lambda: node.pdo[0]) self.assertRaises(KeyError, lambda: node.tpdo[0]) self.assertRaises(KeyError, lambda: node.pdo['DOES NOT EXIST']) + self.assertRaises(KeyError, lambda: node.pdo[0x1BFF]) + self.assertRaises(KeyError, lambda: node.tpdo[0x1BFF]) def test_pdo_maps_iterate(self): node = self.node