Add type hints for internal members of the test cases so type checkers
can ensure the code properly constrains to these types and accounts for
scenarios where the values are `None`.
In most cases, the type checker is allowed to assume the inferred type
upon assignment.
An example is any test case that creates a `Chip` as part of its `setUp`
method. Many of these tests subsequently set the reference to `None` in
`tearDown` to free up resources to be collected by the GC.
If the member was "properly" typed to be `Optional`, all references in
the unit tests would need to be guarded by an assert or a cast or
ignored by the type checker. This is noisy and doesn't add value since
for the life of the test it should always be a valid reference.
Instead, allow `tearDown` to violate the inferred type and inform the
type checker to ignore the assignment via directive.
If the tests are ever changed to set the member to something other than
the inferred type outside of `tearDown`, explicit type hints and proper
checks should be added.
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
Link: https://lore.kernel.org/r/20241114145116.2123714-21-vfazio@xes-inc.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Previously, both tests_edge_event and tests_info_event had a public
module level EventType member.
The __main__ module for unittests does a star import from both modules
which led to an import conflict between the two.
It is not necessary to import EventType to run unit tests.
Now, EventType is private to avoid being imported via star syntax.
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
Link: https://lore.kernel.org/r/20241114145116.2123714-18-vfazio@xes-inc.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Previously, the `test_rising_edge_event` test was defined twice.
The second instance of the test actually tested the falling edge event
and was shadowing the first test which tested the rising edge event.
Now, the second instance is renamed to `test_falling_edge_event` to
reflect what it is testing and to avoid the naming conflict.
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
Link: https://lore.kernel.org/r/20241114145116.2123714-16-vfazio@xes-inc.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Since their inclusion in Python 3.6, f-strings have become the preferred
way to format strings with variable values as they are generally more
readable as the value substitution is in place and doesn't have to be
parsed from the list or arguments to `.format()`.
Where it does not impact readability (when the line is <120 characters),
swap usage of `.format()` to an f-string.
For lines that are not converted, inform the linter to ignore attempts
to upgrade those instances to f-strings [0]
[0]: https://docs.astral.sh/ruff/rules/f-string/
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
Link: https://lore.kernel.org/r/20241114145116.2123714-15-vfazio@xes-inc.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
The `values` argument of `_ext.Request.get_values` uses a preallocated
`list[None]` as a buffer that is populated with `Value`s by the external
module that are then returned from the function.
Use `cast` to inform the type checker it's a `list[Value]` despite how
it's allocated.
Also, as `lines` is typed as an `Iterable`, there is no guarantee it has
a `__len__` method. Instead, use the size of the `offsets` array to
allocate the buffer.
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
Link: https://lore.kernel.org/r/20241114145116.2123714-14-vfazio@xes-inc.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Since `LineRequest._req` is typed to be `Optional` and because type
checkers may not be able to infer that an object is not `None` from an
earlier call (such as `_check_released`) it is necessary to inform type
checkers of the state of the object to silence union-attr [0] errors.
Instead of littering the code with "# type: ignore" comments, use casts
to inform type checkers that objects are not `None`.
Using `assert` is another option, however this duplicates the logic in
`_check_released` so is redundant at best and, at worst, is not a safe
replacement as `assert` can be elided in optimized Python environments
and these checks need to be runtime enforced.
[0]: https://mypy.readthedocs.io/en/stable/error_code_list.html#check-that-attribute-exists-in-each-union-item-union-attr
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
Link: https://lore.kernel.org/r/20241114145116.2123714-12-vfazio@xes-inc.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Since `Chip._chip` is typed to be `Optional` and because type checkers
may not be able to infer that an object is not `None` from an earlier
call (such as `_check_closed`) it is necessary to inform type checkers
of the state of the object to silence union-attr [0] errors.
Instead of littering the code with "# type: ignore" comments, use casts
to inform type checkers that objects are not `None`.
Using `assert` is another option, however this duplicates the logic in
`_check_closed` so is redundant at best and, at worst, is not a safe
replacement as `assert` can be elided in optimized Python environments
and these checks need to be runtime enforced.
[0]: https://mypy.readthedocs.io/en/stable/error_code_list.html#check-that-attribute-exists-in-each-union-item-union-attr
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
Link: https://lore.kernel.org/r/20241114145116.2123714-10-vfazio@xes-inc.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Previously, `Chip.request_lines` and `LineRequest.reconfigure_lines`
were typed to accept a config argument that was either an int, a str,
or a tuple[int | str].
This had two downsides, namely:
* The tuple was typed as having only a single element and not a variable
number of elements. The examples and test suite relied on a variable
length tuple.
* The tuple type itself was overly restictive. The function
implementations had no requirement that the value be a tuple, only
that it was iterable if it was not a str or an int.
Now, these functions accept an Iterable[int | str] instead of tuples to
offer greater flexibility to callers.
This change does not break compatibility for existing users.
Closes: https://github.com/brgl/libgpiod/issues/102
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
Link: https://lore.kernel.org/r/20241114145116.2123714-4-vfazio@xes-inc.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
We no longer use the select module directly in chip.py so drop the
unneeded import.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Previously, the external module relied on gpiod attributes being present
within `globals()` to construct return values back to the caller.
This assumption required callers of the external module to have imported
the attributes to populate `globals()` for the interface to work.
Having this implicit contract is opaque and prone to causing issues if
imports within gpiod modules ever get reworked.
Now, the external module explicitly imports attributes from gpiod in
order to return values back to the caller.
There should be no concern about circular imports as the external module
should be completely imported by the time callers call into it.
Since Py_gpiod_GetGlobalType is no longer used, it has been replaced
with Py_gpiod_GetModuleAttrString which returns a new PyObject*
reference for the named module and attribute that must be decremented
when no longer in use.
Closes: https://github.com/brgl/libgpiod/issues/101
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
Link: https://lore.kernel.org/r/20241008175139.1198980-1-vfazio@xes-inc.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Several files are not being included in distro tarballs so the
functionality of the python build is limited compared to the repo. Add
them to EXTRA_DIST.
Fixes: d588a6a592 ("bindings: python: standalone build tooling for tests")
Fixes: 72d2fa01a2 ("bindings: python: add script to generate sdist and wheels")
Fixes: 85089d0e40 ("bindings: python: add pyproject.toml, pep 518")
Fixes: 389a966d4e ("bindings: python: move long_description into README.md")
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
The purpose of the example is demonstrate using a request with poll().
It provides a hint as to how the poll can be combined with other fds but,
as Python comes with batteries included, the Python version of the example
can be readily extended to actually demonstrate this, as well as how it
can be used in multi-threaded environments.
Extend the example to use an eventfd to allow the poll() to be run in
a background thread and be gracefully terminated by the main thread.
Signed-off-by: Kent Gibson <warthog618@gmail.com>
Link: https://lore.kernel.org/r/20240917125455.324551-1-warthog618@gmail.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Use black to make the coding style of the line-request test cases
consistent with the rest of the codebase.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
We currently only have a test-case that checks if the event clock
property is correctly set in the LineSettings object but not whether it
is actually passed to the line request. Extend the existing test-case for
line requests to account for event clocks as well.
Link: https://lore.kernel.org/r/20240731104658.93117-2-brgl@bgdev.pl
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
When multiple entries are requested using line names in
Chip.request_lines(), only the the last entry is added to
LineRequest._name_map, causing a ValueError when trying to use functions
like LineRequest.set_value() on any former entries.
Move the required variables to the correct scope.
Signed-off-by: Chuang Zhu <git@chuang.cz>
[Bartosz: tweak the commit message]
Co-developed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Reviewed-by: Kent Gibson <warthog618@gmail.com>
Link: https://lore.kernel.org/r/20240710125719.33655-2-brgl@bgdev.pl
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
The kernel's handling of reconfigure with default values, as is the
case for providing a None value as the settings to the Python bindings'
reconfigure_lines(), resets any flags set to non-default values when the
line is requested to their default values. While the flags are cleared,
the kernel makes no corresponding change to the electrical settings -
though subsequent calls to get and set values will apply the updated
flags.
The tests for missing or None settings are extended to demonstrate the
issue for active_low and drive flags, though the issue applies to all
flags.
The tests fail unless the kernel is patched to ignore reconfiguration
of lines without direction set.
Signed-off-by: Kent Gibson <warthog618@gmail.com>
Link: https://lore.kernel.org/r/20240626053808.179457-4-warthog618@gmail.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
The C API requires the configuration passed to reconfigure_lines()
to contain the lines in the same order as they were requested. This is
problematic for the Python bindings which accepts the configuration in
the form of a dict. For versions prior to Python 3.6, dicts do not
maintain insertion order, so iterating over the dict emits lines in
unreliable order.
Even with later Python versions, the ordering requirement makes
reconfigure_lines() awkward to use as subsequent configurations may
group line settings quite differently to the request, yet the user must
go out of their way to reproduce the original ordering.
This is a task better performed by the bindings.
Further, while the documentation for reconfigure_lines() states that
None settings values are treated as default values, the current
implementation raises an error when it tries to dereference the None,
thinking it is an actual object.
Similarly, providing default values for lines for which no settings
are provided would allow support for reconfiguring a subset of
requested lines.
Rework reconfigure_lines() to remove the ordering requirement and
construct the configuration provided to the C API in request order.
Populate missing or None line settings with default values to satisfy
the requirements of the C API that all requested lines must be
reconfigured.
Closes: https://github.com/brgl/libgpiod/issues/54
Signed-off-by: Kent Gibson <warthog618@gmail.com>
Link: https://lore.kernel.org/r/20240626053808.179457-3-warthog618@gmail.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Minor gpiod package release.
Changelog:
- add a script for generating sdist and wheels
- fix make build
- support casting of line.Value to bool
- test fixes
- fix __repr__() implementations
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Make the new test file for line definitions part of the entire test-suite
for python bindings.
Fixes: c8e3ae0499 ("bindings: python: tests: add test for casting line.Value to bool")
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
The __repr__() function should - if possible - return a valid Python
expression that can be used to instantiate a new object when evaluated.
LineSettings.__repr__() is missing comas between arguments. Both Chip and
LineSettings also don't prefix the returned string with 'gpiod.'. Fix
both functions and add more test cases - including actually using the
strings returned by __repr__() to create new objects and compare their
contents.
Reported-by: Robert Thomas <rob.thomas@raspberrypi.com>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
The modules are installed in the .egg directory, and therefore cannot be
imported after that. Additionally PIP tries to remove the global gpiod
module if it's not invoked with the --ignore-installed option.
Specify correct --root and fix the --prefix switch.
Link: https://github.com/pypa/pip/issues/3063
Suggested-by: Maxim Devaev <mdevaev@gmail.com>
Reported-by: Maxim Devaev <mdevaev@gmail.com>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>