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>
Link: https://patch.msgid.link/20261020003728.13669-8-vfazio@gmail.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
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>
Link: https://patch.msgid.link/20261020003728.13669-7-vfazio@gmail.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
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>
Link: https://patch.msgid.link/20261020003728.13669-5-vfazio@gmail.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
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>
Link: https://patch.msgid.link/20261020003728.13669-4-vfazio@gmail.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
If both C++ bindings and the test suite are allowed but catch2 is absent,
meson setup would fail the build with error(). Follow the same *_enabled
graceful handling pattern established for all other optional components:
compute cxx_tests_enabled based on whether catch2 is actually found,
emit a warning() instead of error() when it's missing, and gate the C++
tests subdir on the new flag.
Also: enter the catch2 discovery block based on tests_enabled (instead of
opt_tests.allowed()) so it only runs once the test-suite dependencies
(threads, libgpiosim) are confirmed present.
Add a "C++ tests" line to the Bindings summary section, visible only when
C++ bindings are enabled.
Closes: https://github.com/brgl/libgpiod/discussions/190
Fixes: 97bab4cc87 ("build: replace autotools with meson & ninja")
Link: https://patch.msgid.link/20260622-build-catch2-issue-v1-1-be95e28f310b@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
The top-level meson.build descends into tests/ and dbus/ only when the
computed tests_enabled and dbus_enabled gates are true, so the test
helper libraries and D-Bus executables are only defined in those cases.
The per-component subdirectories instead re-checked opt_*.allowed(),
which is true under the default 'auto' even when the dependencies are
missing, and then referenced those undefined variables - failing the
configuration outright instead of quietly disabling the component.
Gate every subdirectory on the corresponding top-level *_enabled
variable for correct and consistent behavior.
Closes: https://github.com/brgl/libgpiod/discussions/190
Fixes: 97bab4cc87 ("build: replace autotools with meson & ninja")
Link: https://patch.msgid.link/20260617-meson-enabled-checks-v1-1-2ff45c7691fe@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
CHANGELOG.md must now be updated on every python bindings release just
like what we do with the top-level NEWS file. As the existing
description applies to v2.5.0, set the version now that this release is
tagged.
Fixes: 3076847a6c ("bindings: python: gpiod v2.5.0")
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Changelog:
- add support for free-threaded (no-GIL) CPython
- generate wheels for CPython 3.14t (free-threaded)
- drop support for Python 3.9
- migrate the C extension and test modules to multi-phase module
initialization
- release the GIL in chip_get_info()
- fix heap-buffer overflow bugs when setting/getting line values
- check for errors after PyIter_Next() when setting output values
- check for errors after PyIter_Next() when reading request values
- fix reference count imbalances (missing Py_None and line-name
increments, erroneous decref on PyList_SetItem() failure)
- allow closing a Chip multiple times without raising an error
- allow releasing a LineRequest multiple times without raising an error
- remove a duplicated edge-detection setting
- add a CHANGELOG.md to track changes between releases
- copy the license file into source and binary distributions
- require setuptools v77 or newer
- remove wheel from the build dependencies
- add multi-threaded tests
- add a dedicated lint dependency group and update linter configuration
- apply linter recommendations and add type annotations across examples,
setup and helper scripts
- modernize the C extension using upgrade_pythoncapi.py suggestions
- minor internal cleanups and performance improvements
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Since commit a62c732936 ("core: change the behavior of
gpiod_api_version()"), the libgpiod build expects the
GPIOD_API_VERSION_STR external define to contain the API version string.
The setup.py script in python bindings was not updated so it fails to
build the library sources into the generated wheel. Use the correct
define.
Fixes: a62c732936 ("core: change the behavior of gpiod_api_version()")
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
The Event struct wraps a single *mut gpiod_edge_event pointer and is cast
from raw pointers in event_buffer.rs. Without #[repr(transparent)], the
layout compatibility is not guaranteed by the language specification.
Add #[repr(transparent)] to make the pointer cast sound, and replace
try_into().unwrap() with a simple 'as' cast for the sequence number
getters since c_ulong and usize are the same width on Linux.
Fixes: 91f9373c65 ("bindings: rust: Add libgpiod crate")
Assisted-by: Claude Opus 4.6
Reviewed-by: Vincent Fazio <vfazio@xes-inc.com>
Tested-by: Vincent Fazio <vfazio@xes-inc.com>
Link: https://patch.msgid.link/20260604-pre-2-3-fixes-v2-11-781bcaf47475@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
chip::Info already implements PartialEq and PartialOrd (both based on
comparing chip names as UTF-8 strings), but not their total-order
counterparts Eq and Ord. The omission is inconsistent: types with a
total order should implement Ord so callers can use the ergonomic sort()
/ min() / max() APIs.
Add the missing impls. Ord::cmp() delegates to partial_cmp() and falls
back to Ordering::Equal for the unreachable case where a chip name is
not valid UTF-8. Update gpiochip_devices() to use cmp() directly now
that Ord is available.
Assisted-by: Claude Sonnet 4.6
Acked-by: Vincent Fazio <vfazio@xes-inc.com>
Reviewed-by: Vincent Fazio <vfazio@xes-inc.com>
Tested-by: Vincent Fazio <vfazio@xes-inc.com>
Link: https://patch.msgid.link/20260604-pre-2-3-fixes-v2-10-781bcaf47475@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
The direction() method correctly uses get_mapped_value() which converts
std::out_of_range to the project's bad_mapping exception, but bias(),
drive(), edge_detection(), and event_clock() call .at() directly. This
causes them to throw std::out_of_range instead of the expected
bad_mapping exception on unexpected values.
Use get_mapped_value() consistently for all enum mapping lookups.
Fixes: 78020eae9d ("bindings: cxx: remove duplicate mapping helper")
Assisted-by: Claude Opus 4.6
Reviewed-by: Vincent Fazio <vfazio@xes-inc.com>
Tested-by: Vincent Fazio <vfazio@xes-inc.com>
Link: https://patch.msgid.link/20260604-pre-2-3-fixes-v2-8-781bcaf47475@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
It's useful to know which options ended up really being selected by
meson (for instance for --auto-features) so use the dedicated meson
function to display the summary.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Migration to meson broke the sphinx build for docs. Wire the gi-docgen
generation into the meson build and fix docs/conf.py to use the new
build system.
Fixes: 97bab4cc87 ("build: replace autotools with meson & ninja")
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Define and ue the project_url variable instead of repeating the URL in
several places.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Remove leftover mentions of Makefiles from Cargo.toml files in rust
bindings. They are no longer needed after the migration to meson.
Fixes: 97bab4cc87 ("build: replace autotools with meson & ninja")
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
The meson build already generates all pkg-config files via
pkgconfig.generate() in the respective meson.build files. The .pc.in
templates were not cleaned up during the autotools-to-meson migration
and are dead code. Drop them.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Port the project from autotools to meson. All build options are
preserved with the same semantics.
The goal of this change is to produce the same set of files as the
current autotools approach: libraries with correct SONAME/version,
headers, pkg-config files, GObject introspection data, Python extension
modules, D-Bus interface and configuration files. This is done to enable
a one-liner test command running all available test suites.
The only thing we drop is the `make docs` target as it's rarely used and
docs can be generated easily with sphinx directly. They are also not
required for testing.
The Rust workspace is built via a custom target that invokes cargo and
uses SYSTEM_DEPS_* environment variables to point the libgpiod-sys and
gpiosim-sys crates at the locally built C libraries.
In addition to porting the build files to meson, update the docs, remove
unneded items from .gitignore files (or remove them entirely if they're
no longer needed) and update the shunit2 test scripts to no longer care
about source directories.
Tested-by: Erik Wierich <erik@riscstar.com>
Tested-by: Vincent Fazio <vfazio@xes-inc.com>
Link: https://patch.msgid.link/20260428-meson-build-v3-1-8da6976fb0a2@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Previously, tp_new and tp_init functions were defined for Request with
the tp_init function raising a NotImplementedError to prevent the object
from being initialized (__init__, the stage after __new__).
Similar results can be achieved by removing the tp_new and tp_init
functions which raise a slightly different error:
TypeError: cannot create 'gpiod._ext.Request' instances
As this is an internal only detail, there should be impact to users.
Signed-off-by: Vincent Fazio <vfazio@gmail.com>
Link: https://patch.msgid.link/20260423222125.29097-4-vfazio@gmail.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
The PyObject_CallMethod() function jumps through hoops to find the method
to call and to build a stack (if necessary) to call a given method.
In the case of finalizing the request object, that overhead can be
avoided by simply sharing a function with `request_release()` to close the
underlying gpiod_line_request object.
Signed-off-by: Vincent Fazio <vfazio@gmail.com>
Link: https://patch.msgid.link/20260423222125.29097-3-vfazio@gmail.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
The PyObject_CallMethod() function jumps through hoops to find the method
to call and to build a stack (if necessary) to call a given method.
In the case of finalizing the chip object, that overhead can be avoided
by simply sharing a function with `chip_close()` to close the underlying
gpiod_chip object.
Signed-off-by: Vincent Fazio <vfazio@gmail.com>
Link: https://patch.msgid.link/20260423222125.29097-2-vfazio@gmail.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
The C extension methods request_set_values() and request_get_values()
iterate over a caller-supplied sequence and write offsets/values into
pre-allocated buffers self->offsets and self->values, without checking
the write index.
If the user tries to read values for more lines than they previously
requested, we overflow the buffers.
Add appropriate bounds checks and implement test cases for this issue.
Fixes: b7ba732e6a ("treewide: libgpiod v2 implementation")
Reported-by: 4fqr <4fqr@proton.me>
Tested-by: Vincent Fazio <vfazio@xes-inc.com>
Reviewed-by: Vincent Fazio <vfazio@xes-inc.com>
Link: https://patch.msgid.link/20260407-treewide-fixes-v1-1-66c9744a56a3@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Specify useful dependencies for linting the bindings and related code.
The group can be installed with `pip install --group lint`.
As part of this group, specify version ranges for mypy and ruff to keep
linting consistent until new minimal versions of Python are targeted or
until the new annual style introduced by ruff is chosen.
Signed-off-by: Vincent Fazio <vfazio@gmail.com>
Link: https://patch.msgid.link/20260401001459.19159-8-vfazio@gmail.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>