linux-gpio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [libgpiod][PATCH] bindings: python: parse non-tuple Iterable keys
@ 2025-09-02 12:39 Vincent Fazio
  0 siblings, 0 replies; only message in thread
From: Vincent Fazio @ 2025-09-02 12:39 UTC (permalink / raw)
  To: linux-gpio; +Cc: Vincent Fazio, Vincent Fazio

When `chip.request_lines` was modified to allow `Iterable`s instead of
only `tuple`s, the code that checked for duplicate line entries in the
`config` argument was not updated to account for the expanded types.

If the `config` argument had a key that was not a `tuple`, `str`, or
`int`, a `TypeError` would be raised when resolving the line offset.

Refactor the code the resolves IDs to offsets into a separate function
to make the logic a bit clearer and to account for the widened types.

Fixes: 8f62e6c45355 ("bindings: python: loosen type requirements in public API")
Closes: https://github.com/brgl/libgpiod/issues/148
Signed-off-by: Vincent Fazio <vfazio@gmail.com>
---
 bindings/python/gpiod/chip.py               | 23 ++++++++++++++-------
 bindings/python/tests/tests_line_request.py |  4 ++++
 2 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/bindings/python/gpiod/chip.py b/bindings/python/gpiod/chip.py
index 5641343..cccfb03 100644
--- a/bindings/python/gpiod/chip.py
+++ b/bindings/python/gpiod/chip.py
@@ -236,6 +236,20 @@ class Chip:
         self._check_closed()
         return cast(_ext.Chip, self._chip).read_info_event()
 
+    def _resolve_config_keys_to_offsets(
+        self,
+        config_keys: Iterable[Union[Iterable[Union[int, str]], int, str]],
+    ) -> list[int]:
+        offsets: list[int] = list()
+        for key in config_keys:
+            # perform strict int/str check since str is also Iterable
+            if isinstance(key, (int, str)):
+                offsets.append(self.line_offset_from_id(key))
+            else:  # key is an iterable with multiple IDs to resolve
+                for item in key:
+                    offsets.append(self.line_offset_from_id(item))
+        return offsets
+
     def request_lines(
         self,
         config: dict[
@@ -271,14 +285,7 @@ class Chip:
 
         # Sanitize lines - don't allow offset repetitions or offset-name conflicts.
         for offset, count in Counter(
-            [
-                self.line_offset_from_id(line)
-                for line in (
-                    lambda t: [
-                        j for i in (t) for j in (i if isinstance(i, tuple) else (i,))
-                    ]
-                )(tuple(config.keys()))
-            ]
+            self._resolve_config_keys_to_offsets(config_keys=config.keys())
         ).items():
             if count != 1:
                 raise ValueError(
diff --git a/bindings/python/tests/tests_line_request.py b/bindings/python/tests/tests_line_request.py
index afee644..217c299 100644
--- a/bindings/python/tests/tests_line_request.py
+++ b/bindings/python/tests/tests_line_request.py
@@ -101,6 +101,10 @@ class ChipLineRequestWorks(TestCase):
         with self.chip.request_lines(config={(4): None}) as req:
             self.assertEqual(req.offsets, [4])
 
+    def test_request_single_offset_as_frozenset(self) -> None:
+        with self.chip.request_lines(config={frozenset([4]): None}) as req:
+            self.assertEqual(req.offsets, [4])
+
     def test_request_by_name(self) -> None:
         with self.chip.request_lines(config={(1, 2, "foo", "bar"): None}) as req:
             self.assertEqual(req.offsets, [1, 2, 5, 7])
-- 
2.43.0


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2025-09-02 12:39 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-02 12:39 [libgpiod][PATCH] bindings: python: parse non-tuple Iterable keys Vincent Fazio

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).