* [libgpiod][PATCH 01/14] bindings: python: _internal: sort exports
2026-10-20 0:37 [libgpiod][PATCH 00/14] bindings: python: cleanup and support Python 3.15 Vincent Fazio
@ 2026-10-20 0:37 ` Vincent Fazio
2026-10-20 0:37 ` [libgpiod][PATCH 02/14] bindings: python: _internal: simplify poll_fd calculation Vincent Fazio
` (12 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Vincent Fazio @ 2026-10-20 0:37 UTC (permalink / raw)
To: linux-gpio; +Cc: brgl, Vincent Fazio
Ensures the exports in __all__ are sorted alphabetically.
Signed-off-by: Vincent Fazio <vfazio@gmail.com>
---
bindings/python/gpiod/_internal.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bindings/python/gpiod/_internal.py b/bindings/python/gpiod/_internal.py
index b81f970..6ff5b97 100644
--- a/bindings/python/gpiod/_internal.py
+++ b/bindings/python/gpiod/_internal.py
@@ -12,7 +12,7 @@ if TYPE_CHECKING:
from .line_settings import LineSettings
-__all__ = ["poll_fd", "config_iter"]
+__all__ = ["config_iter", "poll_fd"]
def poll_fd(fd: int, timeout: timedelta | float | None = None) -> bool:
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* [libgpiod][PATCH 02/14] bindings: python: _internal: simplify poll_fd calculation
2026-10-20 0:37 [libgpiod][PATCH 00/14] bindings: python: cleanup and support Python 3.15 Vincent Fazio
2026-10-20 0:37 ` [libgpiod][PATCH 01/14] bindings: python: _internal: sort exports Vincent Fazio
@ 2026-10-20 0:37 ` Vincent Fazio
2026-10-20 0:37 ` [libgpiod][PATCH 03/14] bindings: python: _internal: collapse isinstance checks Vincent Fazio
` (11 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Vincent Fazio @ 2026-10-20 0:37 UTC (permalink / raw)
To: linux-gpio; +Cc: brgl, Vincent Fazio
The `True if <> else False` ternary is unnecessary and the return value
can be simplified to the bool result of checking if the file descriptor
is in the list returned from `select`.
Signed-off-by: Vincent Fazio <vfazio@gmail.com>
---
bindings/python/gpiod/_internal.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bindings/python/gpiod/_internal.py b/bindings/python/gpiod/_internal.py
index 6ff5b97..a4c997d 100644
--- a/bindings/python/gpiod/_internal.py
+++ b/bindings/python/gpiod/_internal.py
@@ -23,7 +23,7 @@ def poll_fd(fd: int, timeout: timedelta | float | None = None) -> bool:
sec = timeout
readable, _, _ = select([fd], [], [], sec)
- return True if fd in readable else False
+ return fd in readable
def config_iter(
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* [libgpiod][PATCH 03/14] bindings: python: _internal: collapse isinstance checks
2026-10-20 0:37 [libgpiod][PATCH 00/14] bindings: python: cleanup and support Python 3.15 Vincent Fazio
2026-10-20 0:37 ` [libgpiod][PATCH 01/14] bindings: python: _internal: sort exports Vincent Fazio
2026-10-20 0:37 ` [libgpiod][PATCH 02/14] bindings: python: _internal: simplify poll_fd calculation Vincent Fazio
@ 2026-10-20 0:37 ` Vincent Fazio
2026-10-20 0:37 ` [libgpiod][PATCH 04/14] bindings: python: setup: use a context manager to manage files Vincent Fazio
` (10 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Vincent Fazio @ 2026-10-20 0:37 UTC (permalink / raw)
To: linux-gpio; +Cc: brgl, Vincent Fazio
The two isinstance checks can be combined to a single call that uses a
tuple of types to check against.
When 8c9d5b4 was prototyped, it originally used a single call but it
was falsely micro-optimized to use two separate calls due to the single
call being slower.
The performance overhead was likely due to the tuple of types being
created on each iteration of the loop. Using a module variable with the
proper types avoids this overhead.
$ python3 -m timeit -s "x = 42; T = (int, str)" "isinstance(x, T)"
20000000 loops, best of 5: 13.9 nsec per loop
$ python3 -m timeit -s "x = 42" "isinstance(x, int) or isinstance(x, str)"
20000000 loops, best of 5: 14.6 nsec per loop
$ python3 -m timeit -s "x = 42" "isinstance(x, (int, str))"
10000000 loops, best of 5: 30 nsec per loop
Fixes: 8c9d5b4 ("bindings: python: make config iteration consistent")
Signed-off-by: Vincent Fazio <vfazio@gmail.com>
---
bindings/python/gpiod/_internal.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/bindings/python/gpiod/_internal.py b/bindings/python/gpiod/_internal.py
index a4c997d..f0c7450 100644
--- a/bindings/python/gpiod/_internal.py
+++ b/bindings/python/gpiod/_internal.py
@@ -14,6 +14,8 @@ if TYPE_CHECKING:
__all__ = ["config_iter", "poll_fd"]
+_LINE_ID_TYPES = (int, str)
+
def poll_fd(fd: int, timeout: timedelta | float | None = None) -> bool:
sec: float | None
@@ -30,7 +32,7 @@ def config_iter(
config: dict[Iterable[int | str] | int | str, LineSettings | None],
) -> Generator[tuple[int | str, LineSettings | None]]:
for key, settings in config.items():
- if isinstance(key, int) or isinstance(key, str):
+ if isinstance(key, _LINE_ID_TYPES):
yield key, settings
else:
for subkey in key:
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* [libgpiod][PATCH 04/14] bindings: python: setup: use a context manager to manage files
2026-10-20 0:37 [libgpiod][PATCH 00/14] bindings: python: cleanup and support Python 3.15 Vincent Fazio
` (2 preceding siblings ...)
2026-10-20 0:37 ` [libgpiod][PATCH 03/14] bindings: python: _internal: collapse isinstance checks Vincent Fazio
@ 2026-10-20 0:37 ` Vincent Fazio
2026-10-20 0:37 ` [libgpiod][PATCH 05/14] bindings: python: line: sort exports Vincent Fazio
` (9 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Vincent Fazio @ 2026-10-20 0:37 UTC (permalink / raw)
To: linux-gpio; +Cc: brgl, Vincent Fazio
Previously, a number of places in setup.py did not use a context manager
to manage the lifetime of the underlying file descriptor for reading and
writing the `libgpiod-version.txt` file.
While the previous method works, it relies on the returned file object
being assigned to a temporary Python object that has its refcount
decremented immediately after statement execution. This then relies on
the file object's finalizer to close the underlying handle which can
emit ResourceWarnings:
/bindings/python/setup.py:193: ResourceWarning: unclosed file <_io.TextIOWrapper name='libgpiod-version.txt' mode='w' encoding='UTF-8'>
open("libgpiod-version.txt", "w").write(LIBGPIOD_VERSION)
Now, we specifically use a context manager to close the file descriptor
when done to explicitly manage its lifetime.
Signed-off-by: Vincent Fazio <vfazio@gmail.com>
---
bindings/python/setup.py | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/bindings/python/setup.py b/bindings/python/setup.py
index 7c9a03f..4297615 100644
--- a/bindings/python/setup.py
+++ b/bindings/python/setup.py
@@ -87,10 +87,11 @@ def fetch_tarball(func: Callable[[T], None]) -> Callable[[T], None]:
# If the version in "libgpiod-version.txt" already matches our
# requested tarball, then skip the fetch altogether.
try:
- if open("libgpiod-version.txt").read() == LIBGPIOD_VERSION:
- log.info("skipping tarball fetch")
- func(cmd)
- return
+ with open("libgpiod-version.txt") as f:
+ if f.read() == LIBGPIOD_VERSION:
+ log.info("skipping tarball fetch")
+ func(cmd)
+ return
except OSError:
pass
@@ -185,7 +186,8 @@ def fetch_tarball(func: Callable[[T], None]) -> Callable[[T], None]:
cmd.distribution.metadata.license_files = [LICENSE_FILE] # type: ignore[attr-defined]
# Save the libgpiod version for sdist
- open("libgpiod-version.txt", "w").write(LIBGPIOD_VERSION)
+ with open("libgpiod-version.txt", "w") as f:
+ f.write(LIBGPIOD_VERSION)
# Run the command
func(cmd)
@@ -217,7 +219,8 @@ class build_ext(orig_build_ext):
# Try to get the gpiod version from the .txt file included in sdist
libgpiod_version: str | None
try:
- libgpiod_version = open("libgpiod-version.txt").read()
+ with open("libgpiod-version.txt") as f:
+ libgpiod_version = f.read()
except OSError:
libgpiod_version = LIBGPIOD_VERSION
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* [libgpiod][PATCH 05/14] bindings: python: line: sort exports
2026-10-20 0:37 [libgpiod][PATCH 00/14] bindings: python: cleanup and support Python 3.15 Vincent Fazio
` (3 preceding siblings ...)
2026-10-20 0:37 ` [libgpiod][PATCH 04/14] bindings: python: setup: use a context manager to manage files Vincent Fazio
@ 2026-10-20 0:37 ` Vincent Fazio
2026-10-20 0:37 ` [libgpiod][PATCH 06/14] bindings: python: line_request: simplify __bool__ expression Vincent Fazio
` (8 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Vincent Fazio @ 2026-10-20 0:37 UTC (permalink / raw)
To: linux-gpio; +Cc: brgl, Vincent Fazio
Ensures the exports in __all__ are sorted alphabetically.
Signed-off-by: Vincent Fazio <vfazio@gmail.com>
---
bindings/python/gpiod/line.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bindings/python/gpiod/line.py b/bindings/python/gpiod/line.py
index 0cfc854..47961be 100644
--- a/bindings/python/gpiod/line.py
+++ b/bindings/python/gpiod/line.py
@@ -6,7 +6,7 @@ from enum import Enum
from . import _ext
-__all__ = ["Value", "Direction", "Bias", "Drive", "Edge", "Clock"]
+__all__ = ["Bias", "Clock", "Direction", "Drive", "Edge", "Value"]
class Value(Enum):
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* [libgpiod][PATCH 06/14] bindings: python: line_request: simplify __bool__ expression
2026-10-20 0:37 [libgpiod][PATCH 00/14] bindings: python: cleanup and support Python 3.15 Vincent Fazio
` (4 preceding siblings ...)
2026-10-20 0:37 ` [libgpiod][PATCH 05/14] bindings: python: line: sort exports Vincent Fazio
@ 2026-10-20 0:37 ` Vincent Fazio
2026-10-20 0:37 ` [libgpiod][PATCH 07/14] bindings: python: chip: " Vincent Fazio
` (7 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Vincent Fazio @ 2026-10-20 0:37 UTC (permalink / raw)
To: linux-gpio; +Cc: brgl, Vincent Fazio
The `True if <> else False` ternary is unnecessary and the return value
can be simplified to the bool result of checking if the request object
is not `None`.
The underlying `Request` object does not have an explicit `__bool__`
implementation so the check only proved that the object existed which
is preserved.
Signed-off-by: Vincent Fazio <vfazio@gmail.com>
---
bindings/python/gpiod/line_request.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bindings/python/gpiod/line_request.py b/bindings/python/gpiod/line_request.py
index dc7cd22..077bcc2 100644
--- a/bindings/python/gpiod/line_request.py
+++ b/bindings/python/gpiod/line_request.py
@@ -49,7 +49,7 @@ class LineRequest:
Returns:
True if the request is live and False if it's been released.
"""
- return True if self._req else False
+ return self._req is not None
def __enter__(self) -> LineRequest:
"""
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* [libgpiod][PATCH 07/14] bindings: python: chip: simplify __bool__ expression
2026-10-20 0:37 [libgpiod][PATCH 00/14] bindings: python: cleanup and support Python 3.15 Vincent Fazio
` (5 preceding siblings ...)
2026-10-20 0:37 ` [libgpiod][PATCH 06/14] bindings: python: line_request: simplify __bool__ expression Vincent Fazio
@ 2026-10-20 0:37 ` Vincent Fazio
2026-10-20 0:37 ` [libgpiod][PATCH 08/14] bindings: python: chip: drop redundant exception in reraise Vincent Fazio
` (6 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Vincent Fazio @ 2026-10-20 0:37 UTC (permalink / raw)
To: linux-gpio; +Cc: brgl, Vincent Fazio
The `True if <> else False` ternary is unnecessary and the return value
can be simplified to the bool result of checking if the chip object
is not `None`.
The underlying `Chip` object does not have an explicit `__bool__`
implementation so the check only proved that the object existed which
is preserved.
Signed-off-by: Vincent Fazio <vfazio@gmail.com>
---
bindings/python/gpiod/chip.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bindings/python/gpiod/chip.py b/bindings/python/gpiod/chip.py
index 2acb872..229891f 100644
--- a/bindings/python/gpiod/chip.py
+++ b/bindings/python/gpiod/chip.py
@@ -73,7 +73,7 @@ class Chip:
Returns:
True if the chip is open and False if it's closed.
"""
- return True if self._chip else False
+ return self._chip is not None
def __enter__(self) -> Chip:
"""
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* [libgpiod][PATCH 08/14] bindings: python: chip: drop redundant exception in reraise
2026-10-20 0:37 [libgpiod][PATCH 00/14] bindings: python: cleanup and support Python 3.15 Vincent Fazio
` (6 preceding siblings ...)
2026-10-20 0:37 ` [libgpiod][PATCH 07/14] bindings: python: chip: " Vincent Fazio
@ 2026-10-20 0:37 ` Vincent Fazio
2026-10-20 0:37 ` [libgpiod][PATCH 09/14] bindings: python: chip: use literals for dict/list and declare types Vincent Fazio
` (5 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Vincent Fazio @ 2026-10-20 0:37 UTC (permalink / raw)
To: linux-gpio; +Cc: brgl, Vincent Fazio
When re-raising an exception, it is not necessary to respecify the
exception object.
There is no functional change here; just minor cleanup to squelch new
linter warnings.
Signed-off-by: Vincent Fazio <vfazio@gmail.com>
---
bindings/python/gpiod/chip.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bindings/python/gpiod/chip.py b/bindings/python/gpiod/chip.py
index 229891f..8712b2b 100644
--- a/bindings/python/gpiod/chip.py
+++ b/bindings/python/gpiod/chip.py
@@ -149,7 +149,7 @@ class Chip:
except ValueError:
raise ex
else:
- raise ex
+ raise
else:
offset = id
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* [libgpiod][PATCH 09/14] bindings: python: chip: use literals for dict/list and declare types
2026-10-20 0:37 [libgpiod][PATCH 00/14] bindings: python: cleanup and support Python 3.15 Vincent Fazio
` (7 preceding siblings ...)
2026-10-20 0:37 ` [libgpiod][PATCH 08/14] bindings: python: chip: drop redundant exception in reraise Vincent Fazio
@ 2026-10-20 0:37 ` Vincent Fazio
2026-10-20 0:37 ` [libgpiod][PATCH 10/14] bindings: python: bump ruff linter dependency Vincent Fazio
` (4 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Vincent Fazio @ 2026-10-20 0:37 UTC (permalink / raw)
To: linux-gpio; +Cc: brgl, Vincent Fazio
Use literal constructors for dict ({}) and list ([]) and explicitly type
the variables accordingly.
There is no functional change here; just minor cleanup to squelch new
linter warnings.
Signed-off-by: Vincent Fazio <vfazio@gmail.com>
---
bindings/python/gpiod/chip.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/bindings/python/gpiod/chip.py b/bindings/python/gpiod/chip.py
index 8712b2b..94c432a 100644
--- a/bindings/python/gpiod/chip.py
+++ b/bindings/python/gpiod/chip.py
@@ -275,13 +275,13 @@ class Chip:
for line, value in output_values.items()
}
- name_map = dict()
- requested_lines = list()
- global_output_values = list()
- seen_offsets = set()
+ name_map: dict[str, int] = {}
+ requested_lines: list[int | str] = []
+ global_output_values: list[Value] = []
+ seen_offsets: set[int] = set()
for line, settings in config_iter(config):
- offsets = list()
+ offsets: list[int] = []
offset = self.line_offset_from_id(line)
# don't allow offset repetitions or offset-name conflicts.
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* [libgpiod][PATCH 10/14] bindings: python: bump ruff linter dependency
2026-10-20 0:37 [libgpiod][PATCH 00/14] bindings: python: cleanup and support Python 3.15 Vincent Fazio
` (8 preceding siblings ...)
2026-10-20 0:37 ` [libgpiod][PATCH 09/14] bindings: python: chip: use literals for dict/list and declare types Vincent Fazio
@ 2026-10-20 0:37 ` Vincent Fazio
2026-10-20 0:37 ` [libgpiod][PATCH 11/14] bindings: python: include Python.h before other headers Vincent Fazio
` (3 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Vincent Fazio @ 2026-10-20 0:37 UTC (permalink / raw)
To: linux-gpio; +Cc: brgl, Vincent Fazio
Bump ruff to the recently released 0.17. Most of the important changes
are from 0.16, but there were no incompatibilities found during testing.
Of note is the expansion of the default ruleset [0] which is now
leveraged over the previously selected rules and simplifies the tool
configuration section significantly.
Two things are explicitly disabled as part of this migration:
* Formating of Python blocks in markdown files is disabled [1]
* The typing-extensions flag is set to false since the bindings do not
depend on this package [2] so appropriate lint rules get disabled
As part of this change:
* Unused error suppression flags were removed from
examples/toggle_multiple_line_values.py
* tests/tests_line_requests.py was reformatted to bring it in line
with the rest of the bindings
* The `readlines` call in setup.py has FURB129 [3] suppressed since it
only affects builds (edge case) on 3.10 (now EOL). When the minimal
version is bumped to 3.11, the entire block will go away.
[0]: https://astral.sh/blog/ruff-v0.16.0#better-default-rule-set
[1]: https://docs.astral.sh/ruff/formatter/#markdown-code-formatting
[2]: https://docs.astral.sh/ruff/settings/#lint_typing-extensions
[3]: https://docs.astral.sh/ruff/rules/readlines-in-for/#readlines-in-for-furb129
Signed-off-by: Vincent Fazio <vfazio@gmail.com>
---
.../examples/toggle_multiple_line_values.py | 4 ++--
bindings/python/pyproject.toml | 17 ++++++-----------
bindings/python/setup.py | 2 +-
bindings/python/tests/tests_line_request.py | 3 ++-
4 files changed, 11 insertions(+), 15 deletions(-)
diff --git a/bindings/python/examples/toggle_multiple_line_values.py b/bindings/python/examples/toggle_multiple_line_values.py
index 8c973f8..e5fbcd9 100755
--- a/bindings/python/examples/toggle_multiple_line_values.py
+++ b/bindings/python/examples/toggle_multiple_line_values.py
@@ -29,9 +29,9 @@ def toggle_multiple_line_values(
)
while True:
- print(" ".join(f"{l}={value_str[v]}" for (l, v) in line_values.items())) # noqa: E741
+ print(" ".join(f"{l}={value_str[v]}" for (l, v) in line_values.items()))
time.sleep(1)
- for l, v in line_values.items(): # noqa: E741
+ for l, v in line_values.items():
line_values[l] = toggle_value(v)
request.set_values(line_values)
diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml
index 3337306..7d1c777 100644
--- a/bindings/python/pyproject.toml
+++ b/bindings/python/pyproject.toml
@@ -36,7 +36,7 @@ Issues = "https://github.com/brgl/libgpiod/issues/"
Changelog = "https://github.com/brgl/libgpiod/blob/master/bindings/python/CHANGELOG.md"
[dependency-groups]
-lint = ["mypy>=1.18.1", "ruff~=0.15.0", "types-setuptools", "packaging"]
+lint = ["mypy>=1.18.1", "ruff~=0.17.0", "types-setuptools", "packaging"]
[tool.setuptools]
platforms = ["linux"]
@@ -56,19 +56,14 @@ files = [
".",
]
+[tool.ruff]
+extend-exclude = ["*.md"]
+
[tool.ruff.lint]
-select = ["B", "E", "F", "I", "TC", "UP"]
-ignore=[
- # Ignore chained exception warnings for now: https://docs.astral.sh/ruff/rules/raise-without-from-inside-except/
- "B904",
- # Never enforce line length violations. Let the formatter handle it: https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
- "E501",
-]
+typing-extensions = false
[tool.ruff.lint.per-file-ignores]
-"gpiod/__init__.py" = ["F403", "F405"] # ignore warnings about star imports
-"tests/__main__.py" = ["F403"]
-"tests/**.py" = ["F841"] # ignore warnings about unused variables
+"tests/**.py" = ["F841", "SIM117"] # ignore warnings about unused variables and chaining context managers
[tool.cibuildwheel]
build = "cp*"
diff --git a/bindings/python/setup.py b/bindings/python/setup.py
index 4297615..af922c8 100644
--- a/bindings/python/setup.py
+++ b/bindings/python/setup.py
@@ -167,7 +167,7 @@ def fetch_tarball(func: Callable[[T], None]) -> Callable[[T], None]:
project = cast("dict[str,str]", tomllib.load(f).get("project"))
license_file = project.get("license")
else: # tomllib isn't standard, fall back to parsing by line
- for line in f.readlines():
+ for line in f.readlines(): # noqa: FURB129
_line = line.decode()
if _line.startswith("license = "):
license_file = _line.split("=")[1].strip(' \r\n"')
diff --git a/bindings/python/tests/tests_line_request.py b/bindings/python/tests/tests_line_request.py
index bc85eba..8e74490 100644
--- a/bindings/python/tests/tests_line_request.py
+++ b/bindings/python/tests/tests_line_request.py
@@ -692,7 +692,8 @@ class UsingMoreLinesThanRequestedNotAllowed(TestCase):
def test_line_set_more_values_than_requested_lines(self) -> None:
with gpiod.request_lines(
- self.sim.dev_path, config={0: gpiod.LineSettings(direction=Direction.OUTPUT)}
+ self.sim.dev_path,
+ config={0: gpiod.LineSettings(direction=Direction.OUTPUT)},
) as req:
with self.assertRaises(ValueError):
req.set_values({i: Value.ACTIVE for i in range(64)})
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* [libgpiod][PATCH 11/14] bindings: python: include Python.h before other headers
2026-10-20 0:37 [libgpiod][PATCH 00/14] bindings: python: cleanup and support Python 3.15 Vincent Fazio
` (9 preceding siblings ...)
2026-10-20 0:37 ` [libgpiod][PATCH 10/14] bindings: python: bump ruff linter dependency Vincent Fazio
@ 2026-10-20 0:37 ` Vincent Fazio
2026-10-20 0:37 ` [libgpiod][PATCH 12/14] bindings: python: advertise Python 3.15 support Vincent Fazio
` (2 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Vincent Fazio @ 2026-10-20 0:37 UTC (permalink / raw)
To: linux-gpio; +Cc: brgl, Vincent Fazio
Per the Python C API reference manual [0], Python.h should be included
before other headers since it specifies some pre-processor definitions
that may differ from system defaults.
This was noticed when testing on CPython 3.15 [1] which emitted warnings
due to redefinitions of _XOPEN_SOURCE and _POSIX_C_SOURCE during builds
of the Python bindings.
Note: despite the manual stating that `PY_SSIZE_T_CLEAN` should also be
defined, it is intentionally not included. The Python bindings do not
use the `#` format specifier when parsing any arguments so defining it
provides no value [2] and it is deprecated in future versions.
[0]: https://docs.python.org/3/c-api/intro.html#include-files
[1]: https://github.com/python/cpython/commit/927eb448aad6436d794ec9f55780013e25609600
[2]: https://docs.python.org/3/c-api/arg.html#strings-and-buffers
Signed-off-by: Vincent Fazio <vfazio@gmail.com>
---
bindings/python/gpiod/ext/internal.h | 2 +-
bindings/python/gpiod/ext/module.c | 2 +-
bindings/python/tests/gpiosim/ext.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/bindings/python/gpiod/ext/internal.h b/bindings/python/gpiod/ext/internal.h
index 2996884..12c2ac6 100644
--- a/bindings/python/gpiod/ext/internal.h
+++ b/bindings/python/gpiod/ext/internal.h
@@ -4,8 +4,8 @@
#ifndef __LIBGPIOD_PYTHON_MODULE_H__
#define __LIBGPIOD_PYTHON_MODULE_H__
-#include <gpiod.h>
#include <Python.h>
+#include <gpiod.h>
PyObject *Py_gpiod_SetErrFromErrno(void);
unsigned int Py_gpiod_PyLongAsUnsignedInt(PyObject *pylong);
diff --git a/bindings/python/gpiod/ext/module.c b/bindings/python/gpiod/ext/module.c
index 21ea519..6b5ead7 100644
--- a/bindings/python/gpiod/ext/module.c
+++ b/bindings/python/gpiod/ext/module.c
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
// SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
-#include <gpiod.h>
#include <Python.h>
+#include <gpiod.h>
struct module_const {
const char *name;
diff --git a/bindings/python/tests/gpiosim/ext.c b/bindings/python/tests/gpiosim/ext.c
index cc7bd37..dcdde7b 100644
--- a/bindings/python/tests/gpiosim/ext.c
+++ b/bindings/python/tests/gpiosim/ext.c
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
// SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
-#include <gpiosim.h>
#include <Python.h>
+#include <gpiosim.h>
struct module_const {
const char *name;
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* [libgpiod][PATCH 12/14] bindings: python: advertise Python 3.15 support
2026-10-20 0:37 [libgpiod][PATCH 00/14] bindings: python: cleanup and support Python 3.15 Vincent Fazio
` (10 preceding siblings ...)
2026-10-20 0:37 ` [libgpiod][PATCH 11/14] bindings: python: include Python.h before other headers Vincent Fazio
@ 2026-10-20 0:37 ` Vincent Fazio
2026-10-20 0:37 ` [libgpiod][PATCH 13/14] bindings: python: fix directory validation in artifact script Vincent Fazio
2026-10-20 0:37 ` [libgpiod][PATCH 14/14] bindings: python: bump dependencies " Vincent Fazio
13 siblings, 0 replies; 15+ messages in thread
From: Vincent Fazio @ 2026-10-20 0:37 UTC (permalink / raw)
To: linux-gpio; +Cc: brgl, Vincent Fazio
Add a trove classifier to advertise that the bindings have support for
Python 3.15.
Signed-off-by: Vincent Fazio <vfazio@gmail.com>
---
bindings/python/pyproject.toml | 1 +
1 file changed, 1 insertion(+)
diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml
index 7d1c777..32a4fe3 100644
--- a/bindings/python/pyproject.toml
+++ b/bindings/python/pyproject.toml
@@ -27,6 +27,7 @@ classifiers = [
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
+ "Programming Language :: Python :: 3.15",
"Programming Language :: Python :: Free Threading :: 3 - Stable",
]
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* [libgpiod][PATCH 13/14] bindings: python: fix directory validation in artifact script
2026-10-20 0:37 [libgpiod][PATCH 00/14] bindings: python: cleanup and support Python 3.15 Vincent Fazio
` (11 preceding siblings ...)
2026-10-20 0:37 ` [libgpiod][PATCH 12/14] bindings: python: advertise Python 3.15 support Vincent Fazio
@ 2026-10-20 0:37 ` Vincent Fazio
2026-10-20 0:37 ` [libgpiod][PATCH 14/14] bindings: python: bump dependencies " Vincent Fazio
13 siblings, 0 replies; 15+ messages in thread
From: Vincent Fazio @ 2026-10-20 0:37 UTC (permalink / raw)
To: linux-gpio; +Cc: brgl, Vincent Fazio
The PyPI artifact generation script had two issues with its directory
validation:
* When validating the source directory, it erroneously tested whether
output_dir was a directory instead of source_dir.
* When validating the output directory, it only tested for writability
(-w), which would allow an existing writable regular file to pass
validation and only fail later when copying build artifacts.
Fix the source_dir check to inspect source_dir, and ensure output_dir
is verified to be a directory in addition to being writable.
Fixes: 72d2fa01 ("bindings: python: add script to generate sdist and wheels")
Signed-off-by: Vincent Fazio <vfazio@gmail.com>
---
bindings/python/generate_pypi_artifacts.sh | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/bindings/python/generate_pypi_artifacts.sh b/bindings/python/generate_pypi_artifacts.sh
index 22dad9f..bc8aa05 100755
--- a/bindings/python/generate_pypi_artifacts.sh
+++ b/bindings/python/generate_pypi_artifacts.sh
@@ -58,13 +58,13 @@ while getopts :hv:o:s:cf value; do
esac
done
-if [ -z "${source_dir}" ] || [ ! -d "${output_dir}" ]; then
+if [ -z "${source_dir}" ] || [ ! -d "${source_dir}" ]; then
printf "Invalid source directory %s.\n" "${source_dir}"
exit 1
fi
-if [ -z "${output_dir}" ] || [ ! -w "${output_dir}" ]; then
- printf "Output directory %s is not writable.\n" "${output_dir}"
+if [ -z "${output_dir}" ] || [ ! -d "${output_dir}" ] || [ ! -w "${output_dir}" ]; then
+ printf "Output directory %s is not writable directory.\n" "${output_dir}"
exit 1
fi
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* [libgpiod][PATCH 14/14] bindings: python: bump dependencies in artifact script
2026-10-20 0:37 [libgpiod][PATCH 00/14] bindings: python: cleanup and support Python 3.15 Vincent Fazio
` (12 preceding siblings ...)
2026-10-20 0:37 ` [libgpiod][PATCH 13/14] bindings: python: fix directory validation in artifact script Vincent Fazio
@ 2026-10-20 0:37 ` Vincent Fazio
13 siblings, 0 replies; 15+ messages in thread
From: Vincent Fazio @ 2026-10-20 0:37 UTC (permalink / raw)
To: linux-gpio; +Cc: brgl, Vincent Fazio
Bump the build and cibuildwheel dependencies to take recent fixes.
The new version of cibuildwheel enables building wheels for the recently
release Python 3.15.
Signed-off-by: Vincent Fazio <vfazio@gmail.com>
---
bindings/python/generate_pypi_artifacts.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bindings/python/generate_pypi_artifacts.sh b/bindings/python/generate_pypi_artifacts.sh
index bc8aa05..592dede 100755
--- a/bindings/python/generate_pypi_artifacts.sh
+++ b/bindings/python/generate_pypi_artifacts.sh
@@ -108,7 +108,7 @@ python3 -m "${venv_module}" .venv
venv_python="${temp_dir}/.venv/bin/python"
# Install build dependencies
-${venv_python} -m pip install build==1.3.0 cibuildwheel==3.2.1
+${venv_python} -m pip install build==1.6.1 cibuildwheel==4.3.1
LIBGPIOD_VERSION=${src_version} ${venv_python} -m build --sdist --outdir ./dist "${source_dir}"
sdist=$(find ./dist -name '*.tar.gz')
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread