* [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations
@ 2024-09-27 18:53 Vincent Fazio
2024-09-27 18:53 ` [libgpiod][PATCH 01/22] bindings: python: clean up imports and exports Vincent Fazio
` (22 more replies)
0 siblings, 23 replies; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
This patch series employs mypy [0] and ruff [1] to ensure the gpiod
library has correctly typed public interfaces, is performing proper type
checking internally, is consistently formatted in a standard code style
that targets Python 3.9 syntax, and passes a subset of linting checks.
Patches 1 and 2 remove unused imports, sort the remainder, and ensure
the publicly usable classes are available from the gpiod base module.
Patches 3 and 4 fix and add annotations to the gpiod bindings.
Patches 5-13 fix type and lint errors internal to the bindings.
Patch 14 fixes a duplicate test name identified by the linter.
Patch 15 and 16 remove unused imports, sort the remainder, and fix lint
errors related to a shadowed export.
Patches 17 and 18 fix and add annotations to the test gpiod bindings.
Patches 19-21 fix type and lint errors internal to the tests.
Patch 22 adds mypy and ruff configuration to pyproject.toml and adds
documentation to the readme so future patches can be evaluated against a
standard set of rules.
There should be no functional changes that impact existing code as part
of this series.
All unit tests continue to pass without changes and code coverage has
not changed.
After this series is applied, the public type annotations will reflect
the argument expectations of the class methods so consumers can type
check their code against the gpiod type annotations.
[0]: https://mypy.readthedocs.io/en/stable/
[1]: https://docs.astral.sh/ruff/
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
Vincent Fazio (22):
bindings: python: clean up imports and exports
bindings: python: make internal a private submodule
bindings: python: fix annotation of variable length tuples
bindings: python: add missing method type annotations
bindings: python: add type stubs for _ext
bindings: python: annotate internal members of Chip
bindings: python: fix Chip union-attr type errors
bindings: python: annotate internal members of LineRequest
bindings: python: fix LineRequest union-attr type errors
bindings: python: convert lines to offsets in LineRequest
bindings: python: cast return value of LineRequest.get_values
bindings: python: raise exception type, not exception instance
bindings: python: selectively use f-strings
bindings: python: tests: fix duplicate test name
bindings: python: tests: clean up imports and exports
bindings: python: tests: make EventType private to prevent export
bindings: python: tests: add type stubs for external modules
bindings: python: tests: add missing type annotations
bindings: python: tests: ignore purposeful type errors
bindings: python: tests: annotate internal members
bindings: python: tests: use f-strings
bindings: python: configure and document dev dependencies
bindings/python/README.md | 17 ++
bindings/python/gpiod/__init__.py | 83 ++++++--
bindings/python/gpiod/_ext.pyi | 93 +++++++++
.../python/gpiod/{internal.py => _internal.py} | 3 +-
bindings/python/gpiod/chip.py | 56 ++++--
bindings/python/gpiod/chip_info.py | 6 +-
bindings/python/gpiod/edge_event.py | 9 +-
bindings/python/gpiod/exception.py | 4 +-
bindings/python/gpiod/info_event.py | 11 +-
bindings/python/gpiod/line.py | 5 +-
bindings/python/gpiod/line_info.py | 10 +-
bindings/python/gpiod/line_request.py | 80 +++++---
bindings/python/gpiod/line_settings.py | 15 +-
bindings/python/pyproject.toml | 36 ++++
bindings/python/setup.py | 2 +-
bindings/python/tests/__init__.py | 6 +-
bindings/python/tests/__main__.py | 5 +-
bindings/python/tests/gpiosim/__init__.py | 2 +
bindings/python/tests/gpiosim/_ext.pyi | 21 +++
bindings/python/tests/gpiosim/chip.py | 3 +-
bindings/python/tests/helpers.py | 6 +-
bindings/python/tests/procname/__init__.py | 2 +
bindings/python/tests/procname/_ext.pyi | 1 +
bindings/python/tests/tests_chip.py | 105 ++++++-----
bindings/python/tests/tests_chip_info.py | 38 ++--
bindings/python/tests/tests_edge_event.py | 66 ++++---
bindings/python/tests/tests_info_event.py | 100 ++++++----
bindings/python/tests/tests_line.py | 5 +-
bindings/python/tests/tests_line_info.py | 49 +++--
bindings/python/tests/tests_line_request.py | 210 ++++++++++-----------
bindings/python/tests/tests_line_settings.py | 19 +-
bindings/python/tests/tests_module.py | 37 ++--
32 files changed, 710 insertions(+), 395 deletions(-)
---
base-commit: f6c8c3321d8f30979fa593a4f6546ff3dccd2549
change-id: 20240923-vfazio-mypy-2037e7d5bdd6
Best regards,
--
Vincent Fazio <vfazio@xes-inc.com>
^ permalink raw reply [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 01/22] bindings: python: clean up imports and exports
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 11:16 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 02/22] bindings: python: make internal a private submodule Vincent Fazio
` (21 subsequent siblings)
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
Remove unused imports and sort the remainder following isort rules.
Update submodules to use lists for `__all__` for ease of re-exporting
public classes from within gpiod.
Also, fix instances where `line` wasn't imported via a relative import.
The library now consistently uses relative imports for submodules.
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
bindings/python/gpiod/__init__.py | 66 +++++++++++++++++++++++++++++-----
bindings/python/gpiod/chip.py | 15 ++++----
bindings/python/gpiod/chip_info.py | 2 +-
bindings/python/gpiod/edge_event.py | 5 +--
bindings/python/gpiod/info_event.py | 7 ++--
bindings/python/gpiod/internal.py | 2 +-
bindings/python/gpiod/line.py | 3 +-
bindings/python/gpiod/line_info.py | 6 ++--
bindings/python/gpiod/line_request.py | 9 ++---
bindings/python/gpiod/line_settings.py | 7 ++--
10 files changed, 87 insertions(+), 35 deletions(-)
diff --git a/bindings/python/gpiod/__init__.py b/bindings/python/gpiod/__init__.py
index 9cbb8dfb7b7b8aff4b2f6429fd831d582058c1b6..4d916f7f1a4eabd8ad1b2844262c20ed01a0798c 100644
--- a/bindings/python/gpiod/__init__.py
+++ b/bindings/python/gpiod/__init__.py
@@ -7,19 +7,67 @@ Python bindings for libgpiod.
This module wraps the native C API of libgpiod in a set of python classes.
"""
-from . import _ext
-from . import line
-from .chip import Chip
-from .chip_info import ChipInfo
-from .edge_event import EdgeEvent
-from .exception import ChipClosedError, RequestReleasedError
-from .info_event import InfoEvent
-from .line_request import LineRequest
-from .line_settings import LineSettings
+from . import (
+ _ext,
+ chip,
+ chip_info,
+ edge_event,
+ exception,
+ info_event,
+ line,
+ line_info,
+ line_request,
+ line_settings,
+ version,
+)
+from .chip import *
+from .chip_info import *
+from .edge_event import *
+from .exception import *
+from .info_event import *
+from .line import *
+from .line_info import *
+from .line_request import *
+from .line_settings import *
from .version import __version__
api_version = _ext.api_version
+# public submodules
+__all__ = [
+ "chip",
+ "chip_info",
+ "edge_event",
+ "exception",
+ "info_event",
+ "line",
+ "line_info",
+ "line_request",
+ "line_settings",
+ "version",
+]
+
+# re-export public submodule exports
+__all__ += (
+ chip.__all__
+ + chip_info.__all__
+ + edge_event.__all__
+ + exception.__all__
+ + info_event.__all__
+ + line.__all__
+ + line_info.__all__
+ + line_request.__all__
+ + line_settings.__all__
+)
+
+# module methods/attributes
+__all__ += [
+ "__version__",
+ "api_version",
+ "is_gpiochip_device",
+ "request_lines",
+]
+
def is_gpiochip_device(path: str) -> bool:
"""
diff --git a/bindings/python/gpiod/chip.py b/bindings/python/gpiod/chip.py
index 0a5ac6daac5e44499896958f3453845bf269af2e..257a31eba8d19634fd14e3b1d33a1345a0363946 100644
--- a/bindings/python/gpiod/chip.py
+++ b/bindings/python/gpiod/chip.py
@@ -1,6 +1,11 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
+from collections import Counter
+from datetime import timedelta
+from errno import ENOENT
+from typing import Optional, Union
+
from . import _ext
from .chip_info import ChipInfo
from .exception import ChipClosedError
@@ -8,16 +13,10 @@ from .info_event import InfoEvent
from .internal import poll_fd
from .line import Value
from .line_info import LineInfo
-from .line_settings import LineSettings, _line_settings_to_ext
from .line_request import LineRequest
-from collections import Counter
-from collections.abc import Iterable
-from datetime import timedelta
-from errno import ENOENT
-from select import select
-from typing import Union, Optional
+from .line_settings import LineSettings, _line_settings_to_ext
-__all__ = "Chip"
+__all__ = ["Chip"]
class Chip:
diff --git a/bindings/python/gpiod/chip_info.py b/bindings/python/gpiod/chip_info.py
index 92b5e6f23c7117eaaa3e73ed27305116de7b0af2..884b910681abbc2069673669539d068a93f6aa72 100644
--- a/bindings/python/gpiod/chip_info.py
+++ b/bindings/python/gpiod/chip_info.py
@@ -4,7 +4,7 @@
from dataclasses import dataclass
-__all__ = "ChipInfo"
+__all__ = ["ChipInfo"]
@dataclass(frozen=True, repr=False)
diff --git a/bindings/python/gpiod/edge_event.py b/bindings/python/gpiod/edge_event.py
index bf258c1472abc7b0faa40ed6533c68cefcd85b6b..a8b2378f9e3a9bdfabd8dde60d5c30fc73766f4c 100644
--- a/bindings/python/gpiod/edge_event.py
+++ b/bindings/python/gpiod/edge_event.py
@@ -1,11 +1,12 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
-from . import _ext
from dataclasses import dataclass
from enum import Enum
-__all__ = "EdgeEvent"
+from . import _ext
+
+__all__ = ["EdgeEvent"]
@dataclass(frozen=True, init=False, repr=False)
diff --git a/bindings/python/gpiod/info_event.py b/bindings/python/gpiod/info_event.py
index 481eae6c376bc6cb418e03be84511b0de811ff91..7b544aa6436b34613a71ee06d9b675a63ad16989 100644
--- a/bindings/python/gpiod/info_event.py
+++ b/bindings/python/gpiod/info_event.py
@@ -1,12 +1,13 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
-from . import _ext
-from .line_info import LineInfo
from dataclasses import dataclass
from enum import Enum
-__all__ = "InfoEvent"
+from . import _ext
+from .line_info import LineInfo
+
+__all__ = ["InfoEvent"]
@dataclass(frozen=True, init=False, repr=False)
diff --git a/bindings/python/gpiod/internal.py b/bindings/python/gpiod/internal.py
index 2dddb65027ab6a3f8b590a65050203d3189fb8c8..d1e95e4ade3146f596643d52207b367e332e6f7e 100644
--- a/bindings/python/gpiod/internal.py
+++ b/bindings/python/gpiod/internal.py
@@ -5,7 +5,7 @@ from datetime import timedelta
from select import select
from typing import Optional, Union
-__all__ = []
+__all__ = ["poll_fd"]
def poll_fd(fd: int, timeout: Optional[Union[timedelta, float]] = None) -> bool:
diff --git a/bindings/python/gpiod/line.py b/bindings/python/gpiod/line.py
index d088fb4631cc9f2bf102b6fe9a6ed5dad1eb4420..828385cbd84a95f207e808fe77022caad4056916 100644
--- a/bindings/python/gpiod/line.py
+++ b/bindings/python/gpiod/line.py
@@ -2,9 +2,10 @@
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
-from . import _ext
from enum import Enum
+from . import _ext
+
__all__ = ["Value", "Direction", "Bias", "Drive", "Edge", "Clock"]
diff --git a/bindings/python/gpiod/line_info.py b/bindings/python/gpiod/line_info.py
index c196a6aedeb48223ff5aec27b415c3ac690a84b1..46e16533802e9c8ff57a697e5b51b8b028d0c061 100644
--- a/bindings/python/gpiod/line_info.py
+++ b/bindings/python/gpiod/line_info.py
@@ -1,12 +1,12 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
-from . import _ext
from dataclasses import dataclass
from datetime import timedelta
-from gpiod.line import Direction, Bias, Drive, Edge, Clock
-__all__ = "LineInfo"
+from .line import Bias, Clock, Direction, Drive, Edge
+
+__all__ = ["LineInfo"]
@dataclass(frozen=True, init=False, repr=False)
diff --git a/bindings/python/gpiod/line_request.py b/bindings/python/gpiod/line_request.py
index 51e600a2ee5854f11f12d41ef561ec7bcdeb5908..e48830450dcb5b7fa6c7983a0fe074cd9bd32ab7 100644
--- a/bindings/python/gpiod/line_request.py
+++ b/bindings/python/gpiod/line_request.py
@@ -1,17 +1,18 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
+from collections.abc import Iterable
+from datetime import timedelta
+from typing import Optional, Union
+
from . import _ext
from .edge_event import EdgeEvent
from .exception import RequestReleasedError
from .internal import poll_fd
from .line import Value
from .line_settings import LineSettings, _line_settings_to_ext
-from collections.abc import Iterable
-from datetime import timedelta
-from typing import Optional, Union
-__all__ = "LineRequest"
+__all__ = ["LineRequest"]
class LineRequest:
diff --git a/bindings/python/gpiod/line_settings.py b/bindings/python/gpiod/line_settings.py
index 5e3219438c2812c449d4da84a97ebc420f2b2352..f2811b288f4e832802217e9249a71a4db0eb1a2d 100644
--- a/bindings/python/gpiod/line_settings.py
+++ b/bindings/python/gpiod/line_settings.py
@@ -1,12 +1,13 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
-from . import _ext
from dataclasses import dataclass
from datetime import timedelta
-from gpiod.line import Direction, Bias, Drive, Edge, Clock, Value
-__all__ = "LineSettings"
+from . import _ext
+from .line import Bias, Clock, Direction, Drive, Edge, Value
+
+__all__ = ["LineSettings"]
@dataclass(repr=False)
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 02/22] bindings: python: make internal a private submodule
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
2024-09-27 18:53 ` [libgpiod][PATCH 01/22] bindings: python: clean up imports and exports Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 11:24 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 03/22] bindings: python: fix annotation of variable length tuples Vincent Fazio
` (20 subsequent siblings)
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
The internal submodule shouldn't be exposed as part of the public
interface, so mark it private following PEP 8 convention [0].
Also, add a type annotation to `sec` for its possible types.
[0]: https://peps.python.org/pep-0008/#public-and-internal-interfaces
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
bindings/python/gpiod/{internal.py => _internal.py} | 1 +
bindings/python/gpiod/chip.py | 2 +-
bindings/python/gpiod/line_request.py | 2 +-
3 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/bindings/python/gpiod/internal.py b/bindings/python/gpiod/_internal.py
similarity index 94%
rename from bindings/python/gpiod/internal.py
rename to bindings/python/gpiod/_internal.py
index d1e95e4ade3146f596643d52207b367e332e6f7e..c9b5d2850389d5314a12bf6d151774a96469a085 100644
--- a/bindings/python/gpiod/internal.py
+++ b/bindings/python/gpiod/_internal.py
@@ -9,6 +9,7 @@ __all__ = ["poll_fd"]
def poll_fd(fd: int, timeout: Optional[Union[timedelta, float]] = None) -> bool:
+ sec: Union[float, None]
if isinstance(timeout, timedelta):
sec = timeout.total_seconds()
else:
diff --git a/bindings/python/gpiod/chip.py b/bindings/python/gpiod/chip.py
index 257a31eba8d19634fd14e3b1d33a1345a0363946..1a1bba4d6dd9e840a60394f1b74903f6ad15a0f4 100644
--- a/bindings/python/gpiod/chip.py
+++ b/bindings/python/gpiod/chip.py
@@ -7,10 +7,10 @@ from errno import ENOENT
from typing import Optional, Union
from . import _ext
+from ._internal import poll_fd
from .chip_info import ChipInfo
from .exception import ChipClosedError
from .info_event import InfoEvent
-from .internal import poll_fd
from .line import Value
from .line_info import LineInfo
from .line_request import LineRequest
diff --git a/bindings/python/gpiod/line_request.py b/bindings/python/gpiod/line_request.py
index e48830450dcb5b7fa6c7983a0fe074cd9bd32ab7..154174872e488fa478b27f5e83d65e6040aca367 100644
--- a/bindings/python/gpiod/line_request.py
+++ b/bindings/python/gpiod/line_request.py
@@ -6,9 +6,9 @@ from datetime import timedelta
from typing import Optional, Union
from . import _ext
+from ._internal import poll_fd
from .edge_event import EdgeEvent
from .exception import RequestReleasedError
-from .internal import poll_fd
from .line import Value
from .line_settings import LineSettings, _line_settings_to_ext
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 03/22] bindings: python: fix annotation of variable length tuples
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
2024-09-27 18:53 ` [libgpiod][PATCH 01/22] bindings: python: clean up imports and exports Vincent Fazio
2024-09-27 18:53 ` [libgpiod][PATCH 02/22] bindings: python: make internal a private submodule Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 13:02 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 04/22] bindings: python: add missing method type annotations Vincent Fazio
` (19 subsequent siblings)
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
Both `Chip.request_lines` and `LineRequest.reconfigure_lines` accept a
config argument that is allowed to be either a variable length tuple
of int | str, a str, or an int.
Python documentation [0] points out that variable length tuples need a
trailing ellipsis in their annotation.
[0]: https://docs.python.org/3/library/typing.html#annotating-tuples
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
bindings/python/gpiod/chip.py | 4 +++-
bindings/python/gpiod/line_request.py | 5 ++++-
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/bindings/python/gpiod/chip.py b/bindings/python/gpiod/chip.py
index 1a1bba4d6dd9e840a60394f1b74903f6ad15a0f4..93556b6ea6aa35b9ad6dc0cb840c33cb95170048 100644
--- a/bindings/python/gpiod/chip.py
+++ b/bindings/python/gpiod/chip.py
@@ -222,7 +222,9 @@ class Chip:
def request_lines(
self,
- config: dict[tuple[Union[int, str]], Optional[LineSettings]],
+ config: dict[
+ Union[tuple[Union[int, str], ...], int, str], Optional[LineSettings]
+ ],
consumer: Optional[str] = None,
event_buffer_size: Optional[int] = None,
output_values: Optional[dict[Union[int, str], Value]] = None,
diff --git a/bindings/python/gpiod/line_request.py b/bindings/python/gpiod/line_request.py
index 154174872e488fa478b27f5e83d65e6040aca367..f4e3f06d984d751d842b3c0e77a8db2e0e9a7a60 100644
--- a/bindings/python/gpiod/line_request.py
+++ b/bindings/python/gpiod/line_request.py
@@ -144,7 +144,10 @@ class LineRequest:
self._req.set_values(mapped)
def reconfigure_lines(
- self, config: dict[tuple[Union[int, str]], LineSettings]
+ self,
+ config: dict[
+ Union[tuple[Union[int, str], ...], int, str], Optional[LineSettings]
+ ],
) -> None:
"""
Reconfigure requested lines.
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 04/22] bindings: python: add missing method type annotations
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
` (2 preceding siblings ...)
2024-09-27 18:53 ` [libgpiod][PATCH 03/22] bindings: python: fix annotation of variable length tuples Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 13:07 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 05/22] bindings: python: add type stubs for _ext Vincent Fazio
` (18 subsequent siblings)
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
Explicitly define the arguments for `gpiod.request_lines` so there is a
clearer linkage with the underlying `Chip.request_lines` interface.
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
bindings/python/gpiod/__init__.py | 17 +++++++++++++++--
bindings/python/gpiod/chip.py | 12 ++++++++++--
bindings/python/gpiod/chip_info.py | 2 +-
bindings/python/gpiod/edge_event.py | 2 +-
bindings/python/gpiod/exception.py | 4 ++--
bindings/python/gpiod/info_event.py | 2 +-
bindings/python/gpiod/line.py | 2 +-
bindings/python/gpiod/line_info.py | 2 +-
bindings/python/gpiod/line_request.py | 16 ++++++++++++----
bindings/python/gpiod/line_settings.py | 4 ++--
10 files changed, 46 insertions(+), 17 deletions(-)
diff --git a/bindings/python/gpiod/__init__.py b/bindings/python/gpiod/__init__.py
index 4d916f7f1a4eabd8ad1b2844262c20ed01a0798c..3cf39d61f64c3888584cd2518787b8e17e185ed2 100644
--- a/bindings/python/gpiod/__init__.py
+++ b/bindings/python/gpiod/__init__.py
@@ -7,6 +7,8 @@ Python bindings for libgpiod.
This module wraps the native C API of libgpiod in a set of python classes.
"""
+from typing import Optional, Union
+
from . import (
_ext,
chip,
@@ -83,7 +85,13 @@ def is_gpiochip_device(path: str) -> bool:
return _ext.is_gpiochip_device(path)
-def request_lines(path: str, *args, **kwargs) -> LineRequest:
+def request_lines(
+ path: str,
+ config: dict[Union[tuple[Union[int, str], ...], int, str], Optional[LineSettings]],
+ consumer: Optional[str] = None,
+ event_buffer_size: Optional[int] = None,
+ output_values: Optional[dict[Union[int, str], line.Value]] = None,
+) -> LineRequest:
"""
Open a GPIO chip pointed to by 'path', request lines according to the
configuration arguments, close the chip and return the request object.
@@ -99,4 +107,9 @@ def request_lines(path: str, *args, **kwargs) -> LineRequest:
Returns a new LineRequest object.
"""
with Chip(path) as chip:
- return chip.request_lines(*args, **kwargs)
+ return chip.request_lines(
+ config=config,
+ consumer=consumer,
+ event_buffer_size=event_buffer_size,
+ output_values=output_values,
+ )
diff --git a/bindings/python/gpiod/chip.py b/bindings/python/gpiod/chip.py
index 93556b6ea6aa35b9ad6dc0cb840c33cb95170048..75cc337e74bc965a30962b39a1584b13b4c4b067 100644
--- a/bindings/python/gpiod/chip.py
+++ b/bindings/python/gpiod/chip.py
@@ -1,9 +1,12 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
+from __future__ import annotations
+
from collections import Counter
from datetime import timedelta
from errno import ENOENT
+from types import TracebackType
from typing import Optional, Union
from . import _ext
@@ -66,14 +69,19 @@ class Chip:
"""
return True if self._chip else False
- def __enter__(self):
+ def __enter__(self) -> Chip:
"""
Controlled execution enter callback.
"""
self._check_closed()
return self
- def __exit__(self, exc_type, exc_value, traceback) -> None:
+ def __exit__(
+ self,
+ exc_type: Optional[type[BaseException]],
+ exc_value: Optional[BaseException],
+ traceback: Optional[TracebackType],
+ ) -> None:
"""
Controlled execution exit callback.
"""
diff --git a/bindings/python/gpiod/chip_info.py b/bindings/python/gpiod/chip_info.py
index 884b910681abbc2069673669539d068a93f6aa72..eb585d6d7efa26492163dc0a731ba263d0232099 100644
--- a/bindings/python/gpiod/chip_info.py
+++ b/bindings/python/gpiod/chip_info.py
@@ -17,7 +17,7 @@ class ChipInfo:
label: str
num_lines: int
- def __str__(self):
+ def __str__(self) -> str:
return '<ChipInfo name="{}" label="{}" num_lines={}>'.format(
self.name, self.label, self.num_lines
)
diff --git a/bindings/python/gpiod/edge_event.py b/bindings/python/gpiod/edge_event.py
index a8b2378f9e3a9bdfabd8dde60d5c30fc73766f4c..0d401d896a79dc5204e7ea86f202e37acbd24758 100644
--- a/bindings/python/gpiod/edge_event.py
+++ b/bindings/python/gpiod/edge_event.py
@@ -39,7 +39,7 @@ class EdgeEvent:
object.__setattr__(self, "global_seqno", global_seqno)
object.__setattr__(self, "line_seqno", line_seqno)
- def __str__(self):
+ def __str__(self) -> str:
return "<EdgeEvent type={} timestamp_ns={} line_offset={} global_seqno={} line_seqno={}>".format(
self.event_type,
self.timestamp_ns,
diff --git a/bindings/python/gpiod/exception.py b/bindings/python/gpiod/exception.py
index f9a83c27b73c4ac3a0f4fac1c1b4421b22545645..54208e2ccd9996c0d3256a48ca6ef924a7cce027 100644
--- a/bindings/python/gpiod/exception.py
+++ b/bindings/python/gpiod/exception.py
@@ -9,7 +9,7 @@ class ChipClosedError(Exception):
Error raised when an already closed chip is used.
"""
- def __init__(self):
+ def __init__(self) -> None:
super().__init__("I/O operation on closed chip")
@@ -18,5 +18,5 @@ class RequestReleasedError(Exception):
Error raised when a released request is used.
"""
- def __init__(self):
+ def __init__(self) -> None:
super().__init__("GPIO lines have been released")
diff --git a/bindings/python/gpiod/info_event.py b/bindings/python/gpiod/info_event.py
index 7b544aa6436b34613a71ee06d9b675a63ad16989..d9e9564e21338cd8d1e28c567fa2ed2ac29ceb00 100644
--- a/bindings/python/gpiod/info_event.py
+++ b/bindings/python/gpiod/info_event.py
@@ -30,7 +30,7 @@ class InfoEvent:
object.__setattr__(self, "timestamp_ns", timestamp_ns)
object.__setattr__(self, "line_info", line_info)
- def __str__(self):
+ def __str__(self) -> str:
return "<InfoEvent type={} timestamp_ns={} line_info={}>".format(
self.event_type, self.timestamp_ns, self.line_info
)
diff --git a/bindings/python/gpiod/line.py b/bindings/python/gpiod/line.py
index 828385cbd84a95f207e808fe77022caad4056916..33c73682d2b3231c0754f398ad0a3f2a99854399 100644
--- a/bindings/python/gpiod/line.py
+++ b/bindings/python/gpiod/line.py
@@ -15,7 +15,7 @@ class Value(Enum):
INACTIVE = _ext.VALUE_INACTIVE
ACTIVE = _ext.VALUE_ACTIVE
- def __bool__(self):
+ def __bool__(self) -> bool:
return self == self.ACTIVE
diff --git a/bindings/python/gpiod/line_info.py b/bindings/python/gpiod/line_info.py
index 46e16533802e9c8ff57a697e5b51b8b028d0c061..5ea9568fd5c963c77f53c56ef748ac1e80872ed9 100644
--- a/bindings/python/gpiod/line_info.py
+++ b/bindings/python/gpiod/line_info.py
@@ -58,7 +58,7 @@ class LineInfo:
self, "debounce_period", timedelta(microseconds=debounce_period_us)
)
- def __str__(self):
+ def __str__(self) -> str:
return '<LineInfo offset={} name="{}" used={} consumer="{}" direction={} active_low={} bias={} drive={} edge_detection={} event_clock={} debounced={} debounce_period={}>'.format(
self.offset,
self.name,
diff --git a/bindings/python/gpiod/line_request.py b/bindings/python/gpiod/line_request.py
index f4e3f06d984d751d842b3c0e77a8db2e0e9a7a60..f94b6b50d72486da1446abcda8282a8dc6d6e620 100644
--- a/bindings/python/gpiod/line_request.py
+++ b/bindings/python/gpiod/line_request.py
@@ -1,8 +1,11 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
+from __future__ import annotations
+
from collections.abc import Iterable
from datetime import timedelta
+from types import TracebackType
from typing import Optional, Union
from . import _ext
@@ -38,14 +41,19 @@ class LineRequest:
"""
return True if self._req else False
- def __enter__(self):
+ def __enter__(self) -> LineRequest:
"""
Controlled execution enter callback.
"""
self._check_released()
return self
- def __exit__(self, exc_type, exc_value, traceback):
+ def __exit__(
+ self,
+ exc_type: Optional[type[BaseException]],
+ exc_value: Optional[BaseException],
+ traceback: Optional[TracebackType],
+ ) -> None:
"""
Controlled execution exit callback.
"""
@@ -77,7 +85,7 @@ class LineRequest:
"""
return self.get_values([line])[0]
- def _check_line_name(self, line):
+ def _check_line_name(self, line: Union[int, str]) -> bool:
if isinstance(line, str):
if line not in self._name_map:
raise ValueError("unknown line name: {}".format(line))
@@ -212,7 +220,7 @@ class LineRequest:
return self._req.read_edge_events(max_events)
- def __str__(self):
+ def __str__(self) -> str:
"""
Return a user-friendly, human-readable description of this request.
"""
diff --git a/bindings/python/gpiod/line_settings.py b/bindings/python/gpiod/line_settings.py
index f2811b288f4e832802217e9249a71a4db0eb1a2d..6c6518dbc958423393790a39d69e94802eda8547 100644
--- a/bindings/python/gpiod/line_settings.py
+++ b/bindings/python/gpiod/line_settings.py
@@ -27,7 +27,7 @@ class LineSettings:
# __repr__ generated by @dataclass uses repr for enum members resulting in
# an unusable representation as those are of the form: <NAME: $value>
- def __repr__(self):
+ def __repr__(self) -> str:
return "gpiod.LineSettings(direction=gpiod.line.{}, edge_detection=gpiod.line.{}, bias=gpiod.line.{}, drive=gpiod.line.{}, active_low={}, debounce_period={}, event_clock=gpiod.line.{}, output_value=gpiod.line.{})".format(
str(self.direction),
str(self.edge_detection),
@@ -39,7 +39,7 @@ class LineSettings:
str(self.output_value),
)
- def __str__(self):
+ def __str__(self) -> str:
return "<LineSettings direction={} edge_detection={} bias={} drive={} active_low={} debounce_period={} event_clock={} output_value={}>".format(
self.direction,
self.edge_detection,
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 05/22] bindings: python: add type stubs for _ext
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
` (3 preceding siblings ...)
2024-09-27 18:53 ` [libgpiod][PATCH 04/22] bindings: python: add missing method type annotations Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 13:08 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 06/22] bindings: python: annotate internal members of Chip Vincent Fazio
` (17 subsequent siblings)
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
bindings/python/gpiod/_ext.pyi | 93 ++++++++++++++++++++++++++++++++++++++++++
bindings/python/setup.py | 2 +-
2 files changed, 94 insertions(+), 1 deletion(-)
diff --git a/bindings/python/gpiod/_ext.pyi b/bindings/python/gpiod/_ext.pyi
new file mode 100644
index 0000000000000000000000000000000000000000..1beb80dde9f080b729374b9dc69322c01fc37889
--- /dev/null
+++ b/bindings/python/gpiod/_ext.pyi
@@ -0,0 +1,93 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+# SPDX-FileCopyrightText: 2024 Vincent Fazio <vfazio@gmail.com>
+
+from typing import Optional
+
+from .chip_info import ChipInfo
+from .edge_event import EdgeEvent
+from .info_event import InfoEvent
+from .line import Value
+from .line_info import LineInfo
+
+class LineSettings:
+ def __init__(
+ self,
+ direction: int,
+ edge_detection: int,
+ bias: int,
+ drive: int,
+ active_low: bool,
+ debounce_period: int,
+ event_clock: int,
+ output_value: int,
+ ) -> None: ...
+
+class LineConfig:
+ def __init__(self) -> None: ...
+ def add_line_settings(self, offsets: list[int], settings: LineSettings) -> None: ...
+ def set_output_values(self, global_output_values: list[Value]) -> None: ...
+
+class Request:
+ def release(self) -> None: ...
+ def get_values(self, offsets: list[int], values: list[Value]) -> None: ...
+ def set_values(self, values: dict[int, Value]) -> None: ...
+ def reconfigure_lines(self, line_cfg: LineConfig) -> None: ...
+ def read_edge_events(self, max_events: Optional[int]) -> list[EdgeEvent]: ...
+ @property
+ def chip_name(self) -> str: ...
+ @property
+ def num_lines(self) -> int: ...
+ @property
+ def offsets(self) -> list[int]: ...
+ @property
+ def fd(self) -> int: ...
+
+class Chip:
+ def __init__(self, path: str) -> None: ...
+ def get_info(self) -> ChipInfo: ...
+ def line_offset_from_id(self, id: str) -> int: ...
+ def get_line_info(self, offset: int, watch: bool) -> LineInfo: ...
+ def request_lines(
+ self,
+ line_cfg: LineConfig,
+ consumer: Optional[str],
+ event_buffer_size: Optional[int],
+ ) -> Request: ...
+ def read_info_event(self) -> InfoEvent: ...
+ def close(self) -> None: ...
+ def unwatch_line_info(self, line: int) -> None: ...
+ @property
+ def path(self) -> str: ...
+ @property
+ def fd(self) -> int: ...
+
+def is_gpiochip_device(path: str) -> bool: ...
+
+api_version: str
+
+# enum constants
+BIAS_AS_IS: int
+BIAS_DISABLED: int
+BIAS_PULL_DOWN: int
+BIAS_PULL_UP: int
+BIAS_UNKNOWN: int
+CLOCK_HTE: int
+CLOCK_MONOTONIC: int
+CLOCK_REALTIME: int
+DIRECTION_AS_IS: int
+DIRECTION_INPUT: int
+DIRECTION_OUTPUT: int
+DRIVE_OPEN_DRAIN: int
+DRIVE_OPEN_SOURCE: int
+DRIVE_PUSH_PULL: int
+EDGE_BOTH: int
+EDGE_EVENT_TYPE_FALLING: int
+EDGE_EVENT_TYPE_RISING: int
+EDGE_FALLING: int
+EDGE_NONE: int
+EDGE_RISING: int
+INFO_EVENT_TYPE_LINE_CONFIG_CHANGED: int
+INFO_EVENT_TYPE_LINE_RELEASED: int
+INFO_EVENT_TYPE_LINE_REQUESTED: int
+VALUE_ACTIVE: int
+VALUE_INACTIVE: int
diff --git a/bindings/python/setup.py b/bindings/python/setup.py
index 1f04b9939b47dc7b960679b6f24e87a6f2a4e46f..54790dfd88e77762719fce3d9194499e8ff39d73 100644
--- a/bindings/python/setup.py
+++ b/bindings/python/setup.py
@@ -224,7 +224,7 @@ setup(
name="gpiod",
url="https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git",
packages=find_packages(exclude=["tests", "tests.*"]),
- package_data={"gpiod": ["py.typed"]},
+ package_data={"gpiod": ["py.typed", "_ext.pyi"]},
python_requires=">=3.9.0",
ext_modules=[gpiod_ext],
cmdclass={"build_ext": build_ext, "sdist": sdist},
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 06/22] bindings: python: annotate internal members of Chip
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
` (4 preceding siblings ...)
2024-09-27 18:53 ` [libgpiod][PATCH 05/22] bindings: python: add type stubs for _ext Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 13:09 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 07/22] bindings: python: fix Chip union-attr type errors Vincent Fazio
` (16 subsequent siblings)
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
bindings/python/gpiod/chip.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/bindings/python/gpiod/chip.py b/bindings/python/gpiod/chip.py
index 75cc337e74bc965a30962b39a1584b13b4c4b067..4aa5677f94caf8c5d863aa6d75915a5b650de137 100644
--- a/bindings/python/gpiod/chip.py
+++ b/bindings/python/gpiod/chip.py
@@ -57,8 +57,8 @@ class Chip:
path:
Path to the GPIO character device file.
"""
- self._chip = _ext.Chip(path)
- self._info = None
+ self._chip: Union[_ext.Chip, None] = _ext.Chip(path)
+ self._info: Union[ChipInfo, None] = None
def __bool__(self) -> bool:
"""
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 07/22] bindings: python: fix Chip union-attr type errors
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
` (5 preceding siblings ...)
2024-09-27 18:53 ` [libgpiod][PATCH 06/22] bindings: python: annotate internal members of Chip Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 13:16 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 08/22] bindings: python: annotate internal members of LineRequest Vincent Fazio
` (15 subsequent siblings)
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
Since `Chip._chip` can be `None`, it's necessary to inform type checkers
of the state of the object to silence the union-attr errors.
Type checkers may not be able to infer that an object is not `None` from
an earlier call (such as `_check_closed`).
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.
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
bindings/python/gpiod/chip.py | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/bindings/python/gpiod/chip.py b/bindings/python/gpiod/chip.py
index 4aa5677f94caf8c5d863aa6d75915a5b650de137..fe7bcfe082d6e9f6220093d3fc45ff232b5d0d17 100644
--- a/bindings/python/gpiod/chip.py
+++ b/bindings/python/gpiod/chip.py
@@ -7,7 +7,7 @@ from collections import Counter
from datetime import timedelta
from errno import ENOENT
from types import TracebackType
-from typing import Optional, Union
+from typing import Optional, Union, cast
from . import _ext
from ._internal import poll_fd
@@ -97,6 +97,7 @@ class Chip:
longer be used after this method is called.
"""
self._check_closed()
+ self._chip = cast(_ext.Chip, self._chip)
self._chip.close()
self._chip = None
@@ -108,6 +109,7 @@ class Chip:
New gpiod.ChipInfo object.
"""
self._check_closed()
+ self._chip = cast(_ext.Chip, self._chip)
if not self._info:
self._info = self._chip.get_info()
@@ -132,6 +134,7 @@ class Chip:
so - returns it.
"""
self._check_closed()
+ self._chip = cast(_ext.Chip, self._chip)
if not isinstance(id, int):
try:
@@ -154,6 +157,7 @@ class Chip:
def _get_line_info(self, line: Union[int, str], watch: bool) -> LineInfo:
self._check_closed()
+ self._chip = cast(_ext.Chip, self._chip)
return self._chip.get_line_info(self.line_offset_from_id(line), watch)
def get_line_info(self, line: Union[int, str]) -> LineInfo:
@@ -192,6 +196,7 @@ class Chip:
Offset or name of the line to stop watching.
"""
self._check_closed()
+ self._chip = cast(_ext.Chip, self._chip)
return self._chip.unwatch_line_info(self.line_offset_from_id(line))
def wait_info_event(
@@ -226,6 +231,7 @@ class Chip:
This function may block if there are no available events in the queue.
"""
self._check_closed()
+ self._chip = cast(_ext.Chip, self._chip)
return self._chip.read_info_event()
def request_lines(
@@ -258,6 +264,7 @@ class Chip:
New LineRequest object.
"""
self._check_closed()
+ self._chip = cast(_ext.Chip, self._chip)
line_cfg = _ext.LineConfig()
@@ -362,6 +369,7 @@ class Chip:
Filesystem path used to open this chip.
"""
self._check_closed()
+ self._chip = cast(_ext.Chip, self._chip)
return self._chip.path
@property
@@ -370,4 +378,5 @@ class Chip:
File descriptor associated with this chip.
"""
self._check_closed()
+ self._chip = cast(_ext.Chip, self._chip)
return self._chip.fd
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 08/22] bindings: python: annotate internal members of LineRequest
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
` (6 preceding siblings ...)
2024-09-27 18:53 ` [libgpiod][PATCH 07/22] bindings: python: fix Chip union-attr type errors Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 13:17 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 09/22] bindings: python: fix LineRequest union-attr type errors Vincent Fazio
` (14 subsequent siblings)
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
bindings/python/gpiod/line_request.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/bindings/python/gpiod/line_request.py b/bindings/python/gpiod/line_request.py
index f94b6b50d72486da1446abcda8282a8dc6d6e620..77d199ac64e9d3cc68d4a8b38dd0f571a24ab231 100644
--- a/bindings/python/gpiod/line_request.py
+++ b/bindings/python/gpiod/line_request.py
@@ -30,7 +30,12 @@ class LineRequest:
LineRequest objects can only be instantiated by a Chip parent. This is
not part of stable API.
"""
- self._req = req
+ self._req: Union[_ext.Request, None] = req
+ self._chip_name: str
+ self._offsets: list[int]
+ self._name_map: dict[str, int]
+ self._offset_map: dict[int, str]
+ self._lines: list[Union[int, str]]
def __bool__(self) -> bool:
"""
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 09/22] bindings: python: fix LineRequest union-attr type errors
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
` (7 preceding siblings ...)
2024-09-27 18:53 ` [libgpiod][PATCH 08/22] bindings: python: annotate internal members of LineRequest Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 13:18 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 10/22] bindings: python: convert lines to offsets in LineRequest Vincent Fazio
` (13 subsequent siblings)
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
Since `LineRequest._req` can be `None`, it's necessary to inform type
checkers of the state of the object to silence the union-attr errors.
Type checkers may not be able to infer that an object is not `None` from
an earlier call (such as `_check_released`).
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.
Also, convert singular ints or strs to a tuple instead of a list to keep
with the inferred variable type of `lines`.
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
bindings/python/gpiod/line_request.py | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/bindings/python/gpiod/line_request.py b/bindings/python/gpiod/line_request.py
index 77d199ac64e9d3cc68d4a8b38dd0f571a24ab231..6c57f612a4167061945e798e93f069689723b583 100644
--- a/bindings/python/gpiod/line_request.py
+++ b/bindings/python/gpiod/line_request.py
@@ -6,7 +6,7 @@ from __future__ import annotations
from collections.abc import Iterable
from datetime import timedelta
from types import TracebackType
-from typing import Optional, Union
+from typing import Optional, Union, cast
from . import _ext
from ._internal import poll_fd
@@ -74,6 +74,7 @@ class LineRequest:
not be used after a call to this method.
"""
self._check_released()
+ self._req = cast(_ext.Request, self._req)
self._req.release()
self._req = None
@@ -114,6 +115,7 @@ class LineRequest:
List of logical line values.
"""
self._check_released()
+ self._req = cast(_ext.Request, self._req)
lines = lines or self._lines
@@ -148,6 +150,7 @@ class LineRequest:
Dictionary mapping line offsets or names to desired values.
"""
self._check_released()
+ self._req = cast(_ext.Request, self._req)
mapped = {
self._name_map[line] if self._check_line_name(line) else line: values[line]
@@ -173,13 +176,14 @@ class LineRequest:
Any settings for non-requested lines are ignored.
"""
self._check_released()
+ self._req = cast(_ext.Request, self._req)
line_cfg = _ext.LineConfig()
line_settings = {}
for lines, settings in config.items():
if isinstance(lines, int) or isinstance(lines, str):
- lines = [lines]
+ lines = (lines,)
for line in lines:
offset = self._name_map[line] if self._check_line_name(line) else line
@@ -222,6 +226,7 @@ class LineRequest:
List of read EdgeEvent objects.
"""
self._check_released()
+ self._req = cast(_ext.Request, self._req)
return self._req.read_edge_events(max_events)
@@ -275,4 +280,5 @@ class LineRequest:
File descriptor associated with this request.
"""
self._check_released()
+ self._req = cast(_ext.Request, self._req)
return self._req.fd
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 10/22] bindings: python: convert lines to offsets in LineRequest
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
` (8 preceding siblings ...)
2024-09-27 18:53 ` [libgpiod][PATCH 09/22] bindings: python: fix LineRequest union-attr type errors Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 13:19 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 11/22] bindings: python: cast return value of LineRequest.get_values Vincent Fazio
` (12 subsequent siblings)
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
Remove `_check_line_name` in favor of a new function, `_line_to_offset`,
that converts a line reference to an offset.
This new function helps narrow types and simplifies the iteration logic
that is used to build objects to interface with `_ext.Request`.
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
bindings/python/gpiod/line_request.py | 29 ++++++++++++-----------------
1 file changed, 12 insertions(+), 17 deletions(-)
diff --git a/bindings/python/gpiod/line_request.py b/bindings/python/gpiod/line_request.py
index 6c57f612a4167061945e798e93f069689723b583..a1ca64cfd82c32be5de3fc53f6c981026911bb9c 100644
--- a/bindings/python/gpiod/line_request.py
+++ b/bindings/python/gpiod/line_request.py
@@ -91,14 +91,15 @@ class LineRequest:
"""
return self.get_values([line])[0]
- def _check_line_name(self, line: Union[int, str]) -> bool:
- if isinstance(line, str):
- if line not in self._name_map:
- raise ValueError("unknown line name: {}".format(line))
-
- return True
-
- return False
+ def _line_to_offset(self, line: Union[int, str]) -> int:
+ if isinstance(line, int):
+ return line
+ else:
+ _line: Union[int, None]
+ if (_line := self._name_map.get(line)) is None:
+ raise ValueError(f"unknown line name: {line}")
+ else:
+ return _line
def get_values(
self, lines: Optional[Iterable[Union[int, str]]] = None
@@ -119,10 +120,7 @@ class LineRequest:
lines = lines or self._lines
- offsets = [
- self._name_map[line] if self._check_line_name(line) else line
- for line in lines
- ]
+ offsets = [self._line_to_offset(line) for line in lines]
buf = [None] * len(lines)
@@ -152,10 +150,7 @@ class LineRequest:
self._check_released()
self._req = cast(_ext.Request, self._req)
- mapped = {
- self._name_map[line] if self._check_line_name(line) else line: values[line]
- for line in values
- }
+ mapped = {self._line_to_offset(line): value for line, value in values.items()}
self._req.set_values(mapped)
@@ -186,7 +181,7 @@ class LineRequest:
lines = (lines,)
for line in lines:
- offset = self._name_map[line] if self._check_line_name(line) else line
+ offset = self._line_to_offset(line)
line_settings[offset] = settings
for offset in self.offsets:
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 11/22] bindings: python: cast return value of LineRequest.get_values
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
` (9 preceding siblings ...)
2024-09-27 18:53 ` [libgpiod][PATCH 10/22] bindings: python: convert lines to offsets in LineRequest Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 13:20 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 12/22] bindings: python: raise exception type, not exception instance Vincent Fazio
` (11 subsequent siblings)
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
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>
---
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 a1ca64cfd82c32be5de3fc53f6c981026911bb9c..917020b9ec7046dd8e10158f70efb555fc87eade 100644
--- a/bindings/python/gpiod/line_request.py
+++ b/bindings/python/gpiod/line_request.py
@@ -122,7 +122,7 @@ class LineRequest:
offsets = [self._line_to_offset(line) for line in lines]
- buf = [None] * len(lines)
+ buf = cast(list[Value], [None] * len(offsets))
self._req.get_values(offsets, buf)
return buf
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 12/22] bindings: python: raise exception type, not exception instance
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
` (10 preceding siblings ...)
2024-09-27 18:53 ` [libgpiod][PATCH 11/22] bindings: python: cast return value of LineRequest.get_values Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 13:23 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 13/22] bindings: python: selectively use f-strings Vincent Fazio
` (10 subsequent siblings)
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
This resolves a strict no-untyped-call mypy warning.
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
bindings/python/gpiod/chip.py | 2 +-
bindings/python/gpiod/line_request.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/bindings/python/gpiod/chip.py b/bindings/python/gpiod/chip.py
index fe7bcfe082d6e9f6220093d3fc45ff232b5d0d17..27785d63806619ff70e7c75f7dd102894d3a4ec1 100644
--- a/bindings/python/gpiod/chip.py
+++ b/bindings/python/gpiod/chip.py
@@ -89,7 +89,7 @@ class Chip:
def _check_closed(self) -> None:
if not self._chip:
- raise ChipClosedError()
+ raise ChipClosedError
def close(self) -> None:
"""
diff --git a/bindings/python/gpiod/line_request.py b/bindings/python/gpiod/line_request.py
index 917020b9ec7046dd8e10158f70efb555fc87eade..a9b5105e5cc5bc5f857300ba3e0eb7528ed6ae80 100644
--- a/bindings/python/gpiod/line_request.py
+++ b/bindings/python/gpiod/line_request.py
@@ -66,7 +66,7 @@ class LineRequest:
def _check_released(self) -> None:
if not self._req:
- raise RequestReleasedError()
+ raise RequestReleasedError
def release(self) -> None:
"""
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 13/22] bindings: python: selectively use f-strings
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
` (11 preceding siblings ...)
2024-09-27 18:53 ` [libgpiod][PATCH 12/22] bindings: python: raise exception type, not exception instance Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 13:24 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 14/22] bindings: python: tests: fix duplicate test name Vincent Fazio
` (9 subsequent siblings)
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
Dataclasses are not migrated to f-strings so readability isn't impacted.
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
bindings/python/gpiod/chip.py | 8 +++-----
bindings/python/gpiod/chip_info.py | 2 +-
bindings/python/gpiod/edge_event.py | 2 +-
bindings/python/gpiod/info_event.py | 2 +-
bindings/python/gpiod/line_info.py | 2 +-
bindings/python/gpiod/line_request.py | 2 +-
bindings/python/gpiod/line_settings.py | 4 ++--
7 files changed, 10 insertions(+), 12 deletions(-)
diff --git a/bindings/python/gpiod/chip.py b/bindings/python/gpiod/chip.py
index 27785d63806619ff70e7c75f7dd102894d3a4ec1..e2a82203501160cf63d86a7c8c3e2d92469e2fb9 100644
--- a/bindings/python/gpiod/chip.py
+++ b/bindings/python/gpiod/chip.py
@@ -281,9 +281,7 @@ class Chip:
).items():
if count != 1:
raise ValueError(
- "line must be configured exactly once - offset {} repeats".format(
- offset
- )
+ f"line must be configured exactly once - offset {offset} repeats"
)
# If we have global output values - map line names to offsets
@@ -350,7 +348,7 @@ class Chip:
if not self._chip:
return "<Chip CLOSED>"
- return 'gpiod.Chip("{}")'.format(self.path)
+ return f'gpiod.Chip("{self.path}")'
def __str__(self) -> str:
"""
@@ -359,7 +357,7 @@ class Chip:
if not self._chip:
return "<Chip CLOSED>"
- return '<Chip path="{}" fd={} info={}>'.format(
+ return '<Chip path="{}" fd={} info={}>'.format( # noqa: UP032
self.path, self.fd, self.get_info()
)
diff --git a/bindings/python/gpiod/chip_info.py b/bindings/python/gpiod/chip_info.py
index eb585d6d7efa26492163dc0a731ba263d0232099..27c28131ad4f883f3712e4201a0c325274f5fefc 100644
--- a/bindings/python/gpiod/chip_info.py
+++ b/bindings/python/gpiod/chip_info.py
@@ -18,6 +18,6 @@ class ChipInfo:
num_lines: int
def __str__(self) -> str:
- return '<ChipInfo name="{}" label="{}" num_lines={}>'.format(
+ return '<ChipInfo name="{}" label="{}" num_lines={}>'.format( # noqa: UP032
self.name, self.label, self.num_lines
)
diff --git a/bindings/python/gpiod/edge_event.py b/bindings/python/gpiod/edge_event.py
index 0d401d896a79dc5204e7ea86f202e37acbd24758..7f5cd4d345785ceb549e2888629898818a4ab293 100644
--- a/bindings/python/gpiod/edge_event.py
+++ b/bindings/python/gpiod/edge_event.py
@@ -40,7 +40,7 @@ class EdgeEvent:
object.__setattr__(self, "line_seqno", line_seqno)
def __str__(self) -> str:
- return "<EdgeEvent type={} timestamp_ns={} line_offset={} global_seqno={} line_seqno={}>".format(
+ return "<EdgeEvent type={} timestamp_ns={} line_offset={} global_seqno={} line_seqno={}>".format( # noqa: UP032
self.event_type,
self.timestamp_ns,
self.line_offset,
diff --git a/bindings/python/gpiod/info_event.py b/bindings/python/gpiod/info_event.py
index d9e9564e21338cd8d1e28c567fa2ed2ac29ceb00..ed531f2c3ab36e3c146c87bfdbabd3f95ab8b643 100644
--- a/bindings/python/gpiod/info_event.py
+++ b/bindings/python/gpiod/info_event.py
@@ -31,6 +31,6 @@ class InfoEvent:
object.__setattr__(self, "line_info", line_info)
def __str__(self) -> str:
- return "<InfoEvent type={} timestamp_ns={} line_info={}>".format(
+ return "<InfoEvent type={} timestamp_ns={} line_info={}>".format( # noqa: UP032
self.event_type, self.timestamp_ns, self.line_info
)
diff --git a/bindings/python/gpiod/line_info.py b/bindings/python/gpiod/line_info.py
index 5ea9568fd5c963c77f53c56ef748ac1e80872ed9..1aca142387992d2d836fb2b5672f0b45249691af 100644
--- a/bindings/python/gpiod/line_info.py
+++ b/bindings/python/gpiod/line_info.py
@@ -59,7 +59,7 @@ class LineInfo:
)
def __str__(self) -> str:
- return '<LineInfo offset={} name="{}" used={} consumer="{}" direction={} active_low={} bias={} drive={} edge_detection={} event_clock={} debounced={} debounce_period={}>'.format(
+ return '<LineInfo offset={} name="{}" used={} consumer="{}" direction={} active_low={} bias={} drive={} edge_detection={} event_clock={} debounced={} debounce_period={}>'.format( # noqa: UP032
self.offset,
self.name,
self.used,
diff --git a/bindings/python/gpiod/line_request.py b/bindings/python/gpiod/line_request.py
index a9b5105e5cc5bc5f857300ba3e0eb7528ed6ae80..dcb711095a39002be650aaaf6f158807c37f27e1 100644
--- a/bindings/python/gpiod/line_request.py
+++ b/bindings/python/gpiod/line_request.py
@@ -232,7 +232,7 @@ class LineRequest:
if not self._req:
return "<LineRequest RELEASED>"
- return '<LineRequest chip="{}" num_lines={} offsets={} fd={}>'.format(
+ return '<LineRequest chip="{}" num_lines={} offsets={} fd={}>'.format( # noqa: UP032
self.chip_name, self.num_lines, self.offsets, self.fd
)
diff --git a/bindings/python/gpiod/line_settings.py b/bindings/python/gpiod/line_settings.py
index 6c6518dbc958423393790a39d69e94802eda8547..2aca71c9c5cd02d1add663f5d430dcf0153706b9 100644
--- a/bindings/python/gpiod/line_settings.py
+++ b/bindings/python/gpiod/line_settings.py
@@ -28,7 +28,7 @@ class LineSettings:
# __repr__ generated by @dataclass uses repr for enum members resulting in
# an unusable representation as those are of the form: <NAME: $value>
def __repr__(self) -> str:
- return "gpiod.LineSettings(direction=gpiod.line.{}, edge_detection=gpiod.line.{}, bias=gpiod.line.{}, drive=gpiod.line.{}, active_low={}, debounce_period={}, event_clock=gpiod.line.{}, output_value=gpiod.line.{})".format(
+ return "gpiod.LineSettings(direction=gpiod.line.{}, edge_detection=gpiod.line.{}, bias=gpiod.line.{}, drive=gpiod.line.{}, active_low={}, debounce_period={}, event_clock=gpiod.line.{}, output_value=gpiod.line.{})".format( # noqa: UP032
str(self.direction),
str(self.edge_detection),
str(self.bias),
@@ -40,7 +40,7 @@ class LineSettings:
)
def __str__(self) -> str:
- return "<LineSettings direction={} edge_detection={} bias={} drive={} active_low={} debounce_period={} event_clock={} output_value={}>".format(
+ return "<LineSettings direction={} edge_detection={} bias={} drive={} active_low={} debounce_period={} event_clock={} output_value={}>".format( # noqa: UP032
self.direction,
self.edge_detection,
self.bias,
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 14/22] bindings: python: tests: fix duplicate test name
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
` (12 preceding siblings ...)
2024-09-27 18:53 ` [libgpiod][PATCH 13/22] bindings: python: selectively use f-strings Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 13:25 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 15/22] bindings: python: tests: clean up imports and exports Vincent Fazio
` (8 subsequent siblings)
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
bindings/python/tests/tests_edge_event.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bindings/python/tests/tests_edge_event.py b/bindings/python/tests/tests_edge_event.py
index 17b27026356be60b6e928cff04917f487947824c..68ab17eae7be301cbca8d6d83f90a03df0aeea53 100644
--- a/bindings/python/tests/tests_edge_event.py
+++ b/bindings/python/tests/tests_edge_event.py
@@ -118,7 +118,7 @@ class WaitingForEdgeEvents(TestCase):
self.assertFalse(req.wait_edge_events(timedelta(microseconds=10000)))
- def test_rising_edge_event(self):
+ def test_falling_edge_event(self):
with gpiod.request_lines(
self.sim.dev_path, {6: gpiod.LineSettings(edge_detection=Edge.FALLING)}
) as req:
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 15/22] bindings: python: tests: clean up imports and exports
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
` (13 preceding siblings ...)
2024-09-27 18:53 ` [libgpiod][PATCH 14/22] bindings: python: tests: fix duplicate test name Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 13:27 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 16/22] bindings: python: tests: make EventType private to prevent export Vincent Fazio
` (7 subsequent siblings)
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
bindings/python/tests/__init__.py | 2 --
bindings/python/tests/__main__.py | 5 ++---
bindings/python/tests/gpiosim/__init__.py | 2 ++
bindings/python/tests/gpiosim/chip.py | 3 ++-
bindings/python/tests/procname/__init__.py | 2 ++
bindings/python/tests/tests_chip.py | 5 +++--
bindings/python/tests/tests_chip_info.py | 3 ++-
bindings/python/tests/tests_edge_event.py | 9 +++++----
bindings/python/tests/tests_info_event.py | 10 +++++-----
bindings/python/tests/tests_line.py | 3 ++-
bindings/python/tests/tests_line_info.py | 12 ++++++------
bindings/python/tests/tests_line_request.py | 6 +++---
bindings/python/tests/tests_line_settings.py | 7 +++----
bindings/python/tests/tests_module.py | 7 +++----
14 files changed, 40 insertions(+), 36 deletions(-)
diff --git a/bindings/python/tests/__init__.py b/bindings/python/tests/__init__.py
index 02f4e8d59c9aa426ca23a8ff2be4aa8aed8784c2..2374e8155373efbd94d5c66dcfdffa7cc23be9f6 100644
--- a/bindings/python/tests/__init__.py
+++ b/bindings/python/tests/__init__.py
@@ -2,8 +2,6 @@
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
import os
-import unittest
-
from distutils.version import LooseVersion
required_kernel_version = LooseVersion("5.19.0")
diff --git a/bindings/python/tests/__main__.py b/bindings/python/tests/__main__.py
index ea4143f53de5ac7d6202508216c7021ad3673b37..8b4260dfeeb39495b9b98fb096f8d3559e7ad7d3 100644
--- a/bindings/python/tests/__main__.py
+++ b/bindings/python/tests/__main__.py
@@ -4,17 +4,16 @@
import unittest
+from . import procname
from .tests_chip import *
from .tests_chip_info import *
from .tests_edge_event import *
from .tests_info_event import *
from .tests_line import *
from .tests_line_info import *
+from .tests_line_request import *
from .tests_line_settings import *
from .tests_module import *
-from .tests_line_request import *
-
-from . import procname
procname.set_process_name("python-gpiod")
diff --git a/bindings/python/tests/gpiosim/__init__.py b/bindings/python/tests/gpiosim/__init__.py
index f65e413a6e8a578607f24c179f34308228dd5cea..64a15511df70863a14e134c1986ea625f4701dd6 100644
--- a/bindings/python/tests/gpiosim/__init__.py
+++ b/bindings/python/tests/gpiosim/__init__.py
@@ -2,3 +2,5 @@
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
from .chip import Chip
+
+__all__ = ["Chip"]
diff --git a/bindings/python/tests/gpiosim/chip.py b/bindings/python/tests/gpiosim/chip.py
index 6af883ee3152aee2976e674647a218d34d4dbf7e..691bfe13084b3fcc109dffc64866fb901d7d8069 100644
--- a/bindings/python/tests/gpiosim/chip.py
+++ b/bindings/python/tests/gpiosim/chip.py
@@ -1,10 +1,11 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
-from . import _ext
from enum import Enum
from typing import Optional
+from . import _ext
+
class Chip:
"""
diff --git a/bindings/python/tests/procname/__init__.py b/bindings/python/tests/procname/__init__.py
index af6abdd2586a95c83234ac9a6f445e3e33e71866..436ff406fec30f7711dd1bb3f95024a6c530d45a 100644
--- a/bindings/python/tests/procname/__init__.py
+++ b/bindings/python/tests/procname/__init__.py
@@ -2,3 +2,5 @@
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
from ._ext import set_process_name
+
+__all__ = ["set_process_name"]
diff --git a/bindings/python/tests/tests_chip.py b/bindings/python/tests/tests_chip.py
index bd4ae34cd618a972417e314b36ed527675627fbc..9110bebf3596557fbacb3c7620e931982f9dc957 100644
--- a/bindings/python/tests/tests_chip.py
+++ b/bindings/python/tests/tests_chip.py
@@ -2,12 +2,13 @@
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
import errno
-import gpiod
import os
+from unittest import TestCase
+
+import gpiod
from . import gpiosim
from .helpers import LinkGuard
-from unittest import TestCase
class ChipConstructor(TestCase):
diff --git a/bindings/python/tests/tests_chip_info.py b/bindings/python/tests/tests_chip_info.py
index d392ec3beaf027326ae91952b917f0d6aae61fd0..9474f38be3d33e60529e0e24fb4f10cb99ce9d5c 100644
--- a/bindings/python/tests/tests_chip_info.py
+++ b/bindings/python/tests/tests_chip_info.py
@@ -1,10 +1,11 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
+from unittest import TestCase
+
import gpiod
from . import gpiosim
-from unittest import TestCase
class ChipInfoProperties(TestCase):
diff --git a/bindings/python/tests/tests_edge_event.py b/bindings/python/tests/tests_edge_event.py
index 68ab17eae7be301cbca8d6d83f90a03df0aeea53..7e7fada38cf2a983172aaa9c8400fbfe0d3b7a7d 100644
--- a/bindings/python/tests/tests_edge_event.py
+++ b/bindings/python/tests/tests_edge_event.py
@@ -1,16 +1,17 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
-import gpiod
import time
-
-from . import gpiosim
from datetime import timedelta
from functools import partial
-from gpiod.line import Direction, Edge
from threading import Thread
from unittest import TestCase
+import gpiod
+from gpiod.line import Direction, Edge
+
+from . import gpiosim
+
EventType = gpiod.EdgeEvent.Type
Pull = gpiosim.Chip.Pull
diff --git a/bindings/python/tests/tests_info_event.py b/bindings/python/tests/tests_info_event.py
index a226e52a282347f7514a46f854a9dd5a06a50be8..bbdbc0fa6e69c59a32d67d00f5e785105c90e840 100644
--- a/bindings/python/tests/tests_info_event.py
+++ b/bindings/python/tests/tests_info_event.py
@@ -3,17 +3,17 @@
import datetime
import errno
-import gpiod
import threading
import time
-import unittest
-
-from . import gpiosim
from dataclasses import FrozenInstanceError
from functools import partial
-from gpiod.line import Direction
from unittest import TestCase
+import gpiod
+from gpiod.line import Direction
+
+from . import gpiosim
+
EventType = gpiod.InfoEvent.Type
diff --git a/bindings/python/tests/tests_line.py b/bindings/python/tests/tests_line.py
index 70aa09bda2033bab7d7e59ea4ff48b2b783da468..218256711b2b248f692f07b9ae99e462f03c6965 100644
--- a/bindings/python/tests/tests_line.py
+++ b/bindings/python/tests/tests_line.py
@@ -1,9 +1,10 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# SPDX-FileCopyrightText: 2024 Kent Gibson <warthog618@gmail.com>
-from gpiod.line import Value
from unittest import TestCase
+from gpiod.line import Value
+
class LineValue(TestCase):
def test_cast_bool(self):
diff --git a/bindings/python/tests/tests_line_info.py b/bindings/python/tests/tests_line_info.py
index 2779e7a7353c95b35f78ab96311a418af41ffdbc..79281a82932a32bdb8c89f2aac7b15eb28eafd9d 100644
--- a/bindings/python/tests/tests_line_info.py
+++ b/bindings/python/tests/tests_line_info.py
@@ -1,17 +1,17 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
-import errno
+from unittest import TestCase
+
import gpiod
-import unittest
+from gpiod.line import Bias, Clock, Direction, Drive
from . import gpiosim
-from gpiod.line import Direction, Bias, Drive, Clock
HogDir = gpiosim.Chip.Direction
-class GetLineInfo(unittest.TestCase):
+class GetLineInfo(TestCase):
def setUp(self):
self.sim = gpiosim.Chip(
num_lines=4,
@@ -49,7 +49,7 @@ class GetLineInfo(unittest.TestCase):
self.chip.get_line_info()
-class LinePropertiesCanBeRead(unittest.TestCase):
+class LinePropertiesCanBeRead(TestCase):
def test_basic_properties(self):
sim = gpiosim.Chip(
num_lines=8,
@@ -86,7 +86,7 @@ class LinePropertiesCanBeRead(unittest.TestCase):
self.assertEqual(info6.debounce_period.total_seconds(), 0.0)
-class LineInfoStringRepresentation(unittest.TestCase):
+class LineInfoStringRepresentation(TestCase):
def test_line_info_str(self):
sim = gpiosim.Chip(
line_names={0: "foo"}, hogs={0: ("hogger", HogDir.OUTPUT_HIGH)}
diff --git a/bindings/python/tests/tests_line_request.py b/bindings/python/tests/tests_line_request.py
index 285c9f1e6f43c9623880e91923b0019575adf768..c3e86c56be63f7e449c07e7833cb7080ee42b0ac 100644
--- a/bindings/python/tests/tests_line_request.py
+++ b/bindings/python/tests/tests_line_request.py
@@ -1,12 +1,12 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
-import errno
+from unittest import TestCase
+
import gpiod
+from gpiod.line import Clock, Direction, Drive, Edge, Value
from . import gpiosim
-from gpiod.line import Clock, Direction, Drive, Edge, Value
-from unittest import TestCase
Pull = gpiosim.Chip.Pull
SimVal = gpiosim.Chip.Value
diff --git a/bindings/python/tests/tests_line_settings.py b/bindings/python/tests/tests_line_settings.py
index 83be3d9a90b9391ffe9cb3fb09c1a4a2042468c6..832ac8a2377ddb25f5a5ab5c1732d1a9d5c5dff1 100644
--- a/bindings/python/tests/tests_line_settings.py
+++ b/bindings/python/tests/tests_line_settings.py
@@ -2,12 +2,11 @@
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
import datetime
-import gpiod
-
-from . import gpiosim
-from gpiod.line import Direction, Edge, Bias, Drive, Value, Clock
from unittest import TestCase
+import gpiod
+from gpiod.line import Bias, Clock, Direction, Drive, Edge, Value
+
class LineSettingsConstructor(TestCase):
def test_default_values(self):
diff --git a/bindings/python/tests/tests_module.py b/bindings/python/tests/tests_module.py
index c6f07a618b2c19e6afae9b1bf48747b086c8919a..f46729feda86962d17907bc8b6b4e710fec3087e 100644
--- a/bindings/python/tests/tests_module.py
+++ b/bindings/python/tests/tests_module.py
@@ -1,13 +1,13 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
-import gpiod
import os
-import unittest
+from unittest import TestCase
+
+import gpiod
from . import gpiosim
from .helpers import LinkGuard
-from unittest import TestCase
class IsGPIOChip(TestCase):
@@ -50,7 +50,6 @@ class IsGPIOChip(TestCase):
class VersionString(TestCase):
-
VERSION_PATTERN = "^\\d+\\.\\d+(\\.\\d+|\\-devel|\\-rc\\d+)?$"
def test_api_version_string(self):
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 16/22] bindings: python: tests: make EventType private to prevent export
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
` (14 preceding siblings ...)
2024-09-27 18:53 ` [libgpiod][PATCH 15/22] bindings: python: tests: clean up imports and exports Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 13:29 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 17/22] bindings: python: tests: add type stubs for external modules Vincent Fazio
` (6 subsequent siblings)
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
bindings/python/tests/tests_edge_event.py | 14 +++++++-------
bindings/python/tests/tests_info_event.py | 10 +++++-----
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/bindings/python/tests/tests_edge_event.py b/bindings/python/tests/tests_edge_event.py
index 7e7fada38cf2a983172aaa9c8400fbfe0d3b7a7d..c24d344fdbd6a1b9eda9497afab8a61c5ecb8f09 100644
--- a/bindings/python/tests/tests_edge_event.py
+++ b/bindings/python/tests/tests_edge_event.py
@@ -12,7 +12,7 @@ from gpiod.line import Direction, Edge
from . import gpiosim
-EventType = gpiod.EdgeEvent.Type
+_EventType = gpiod.EdgeEvent.Type
Pull = gpiosim.Chip.Pull
@@ -87,7 +87,7 @@ class WaitingForEdgeEvents(TestCase):
events = req.read_edge_events()
self.assertEqual(len(events), 1)
event = events[0]
- self.assertEqual(event.event_type, EventType.RISING_EDGE)
+ self.assertEqual(event.event_type, _EventType.RISING_EDGE)
self.assertEqual(event.line_offset, 2)
ts_rising = event.timestamp_ns
@@ -95,7 +95,7 @@ class WaitingForEdgeEvents(TestCase):
events = req.read_edge_events()
self.assertEqual(len(events), 1)
event = events[0]
- self.assertEqual(event.event_type, EventType.FALLING_EDGE)
+ self.assertEqual(event.event_type, _EventType.FALLING_EDGE)
self.assertEqual(event.line_offset, 2)
ts_falling = event.timestamp_ns
@@ -114,7 +114,7 @@ class WaitingForEdgeEvents(TestCase):
events = req.read_edge_events()
self.assertEqual(len(events), 1)
event = events[0]
- self.assertEqual(event.event_type, EventType.RISING_EDGE)
+ self.assertEqual(event.event_type, _EventType.RISING_EDGE)
self.assertEqual(event.line_offset, 6)
self.assertFalse(req.wait_edge_events(timedelta(microseconds=10000)))
@@ -132,7 +132,7 @@ class WaitingForEdgeEvents(TestCase):
events = req.read_edge_events()
self.assertEqual(len(events), 1)
event = events[0]
- self.assertEqual(event.event_type, EventType.FALLING_EDGE)
+ self.assertEqual(event.event_type, _EventType.FALLING_EDGE)
self.assertEqual(event.line_offset, 6)
self.assertFalse(req.wait_edge_events(timedelta(microseconds=10000)))
@@ -150,7 +150,7 @@ class WaitingForEdgeEvents(TestCase):
events = req.read_edge_events()
self.assertEqual(len(events), 1)
event = events[0]
- self.assertEqual(event.event_type, EventType.RISING_EDGE)
+ self.assertEqual(event.event_type, _EventType.RISING_EDGE)
self.assertEqual(event.line_offset, 2)
self.assertEqual(event.global_seqno, 1)
self.assertEqual(event.line_seqno, 1)
@@ -159,7 +159,7 @@ class WaitingForEdgeEvents(TestCase):
events = req.read_edge_events()
self.assertEqual(len(events), 1)
event = events[0]
- self.assertEqual(event.event_type, EventType.RISING_EDGE)
+ self.assertEqual(event.event_type, _EventType.RISING_EDGE)
self.assertEqual(event.line_offset, 4)
self.assertEqual(event.global_seqno, 2)
self.assertEqual(event.line_seqno, 1)
diff --git a/bindings/python/tests/tests_info_event.py b/bindings/python/tests/tests_info_event.py
index bbdbc0fa6e69c59a32d67d00f5e785105c90e840..1976f4be8b9a63942275875ada00472402524350 100644
--- a/bindings/python/tests/tests_info_event.py
+++ b/bindings/python/tests/tests_info_event.py
@@ -14,7 +14,7 @@ from gpiod.line import Direction
from . import gpiosim
-EventType = gpiod.InfoEvent.Type
+_EventType = gpiod.InfoEvent.Type
class InfoEventDataclassBehavior(TestCase):
@@ -101,7 +101,7 @@ class WatchingInfoEventWorks(TestCase):
self.assertTrue(self.chip.wait_info_event(datetime.timedelta(seconds=1)))
event = self.chip.read_info_event()
- self.assertEqual(event.event_type, EventType.LINE_REQUESTED)
+ self.assertEqual(event.event_type, _EventType.LINE_REQUESTED)
self.assertEqual(event.line_info.offset, 7)
self.assertEqual(event.line_info.direction, Direction.INPUT)
ts_req = event.timestamp_ns
@@ -109,14 +109,14 @@ class WatchingInfoEventWorks(TestCase):
# Check that we can use a float directly instead of datetime.timedelta.
self.assertTrue(self.chip.wait_info_event(1.0))
event = self.chip.read_info_event()
- self.assertEqual(event.event_type, EventType.LINE_CONFIG_CHANGED)
+ self.assertEqual(event.event_type, _EventType.LINE_CONFIG_CHANGED)
self.assertEqual(event.line_info.offset, 7)
self.assertEqual(event.line_info.direction, Direction.OUTPUT)
ts_rec = event.timestamp_ns
self.assertTrue(self.chip.wait_info_event(datetime.timedelta(seconds=1)))
event = self.chip.read_info_event()
- self.assertEqual(event.event_type, EventType.LINE_RELEASED)
+ self.assertEqual(event.event_type, _EventType.LINE_RELEASED)
self.assertEqual(event.line_info.offset, 7)
self.assertEqual(event.line_info.direction, Direction.OUTPUT)
ts_rel = event.timestamp_ns
@@ -146,7 +146,7 @@ class UnwatchingLineInfo(TestCase):
with self.chip.request_lines(config={0: None}) as request:
self.assertTrue(self.chip.wait_info_event(datetime.timedelta(seconds=1)))
event = self.chip.read_info_event()
- self.assertEqual(event.event_type, EventType.LINE_REQUESTED)
+ self.assertEqual(event.event_type, _EventType.LINE_REQUESTED)
self.chip.unwatch_line_info(0)
self.assertFalse(
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 17/22] bindings: python: tests: add type stubs for external modules
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
` (15 preceding siblings ...)
2024-09-27 18:53 ` [libgpiod][PATCH 16/22] bindings: python: tests: make EventType private to prevent export Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 13:30 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 18/22] bindings: python: tests: add missing type annotations Vincent Fazio
` (5 subsequent siblings)
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
bindings/python/tests/gpiosim/_ext.pyi | 21 +++++++++++++++++++++
bindings/python/tests/procname/_ext.pyi | 1 +
2 files changed, 22 insertions(+)
diff --git a/bindings/python/tests/gpiosim/_ext.pyi b/bindings/python/tests/gpiosim/_ext.pyi
new file mode 100644
index 0000000000000000000000000000000000000000..69d4b63cf54af25f9f029a68d36a9a63789ce132
--- /dev/null
+++ b/bindings/python/tests/gpiosim/_ext.pyi
@@ -0,0 +1,21 @@
+class Chip:
+ def __init__(self) -> None: ...
+ def set_label(self, label: str) -> None: ...
+ def set_num_lines(self, num_lines: int) -> None: ...
+ def set_line_name(self, offset: int, name: str) -> None: ...
+ def set_hog(self, offset: int, name: str, direction: int) -> None: ...
+ def enable(self) -> None: ...
+ def get_value(set, offset: int) -> int: ...
+ def set_pull(set, offset: int, pull: int) -> None: ...
+ @property
+ def dev_path(self) -> str: ...
+ @property
+ def name(self) -> str: ...
+
+PULL_DOWN: int
+PULL_UP: int
+VALUE_INACTIVE: int
+VALUE_ACTIVE: int
+DIRECTION_INPUT: int
+DIRECTION_OUTPUT_HIGH: int
+DIRECTION_OUTPUT_LOW: int
diff --git a/bindings/python/tests/procname/_ext.pyi b/bindings/python/tests/procname/_ext.pyi
new file mode 100644
index 0000000000000000000000000000000000000000..fdcd8ac15f2a0cb9b900ef272b2a10818c8eef4e
--- /dev/null
+++ b/bindings/python/tests/procname/_ext.pyi
@@ -0,0 +1 @@
+def set_process_name(name: str) -> None: ...
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 18/22] bindings: python: tests: add missing type annotations
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
` (16 preceding siblings ...)
2024-09-27 18:53 ` [libgpiod][PATCH 17/22] bindings: python: tests: add type stubs for external modules Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 13:32 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 19/22] bindings: python: tests: ignore purposeful type errors Vincent Fazio
` (4 subsequent siblings)
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
bindings/python/tests/helpers.py | 6 +-
bindings/python/tests/tests_chip.py | 68 +++++-----
bindings/python/tests/tests_chip_info.py | 14 +-
bindings/python/tests/tests_edge_event.py | 32 ++---
bindings/python/tests/tests_info_event.py | 38 +++---
bindings/python/tests/tests_line.py | 2 +-
bindings/python/tests/tests_line_info.py | 22 ++--
bindings/python/tests/tests_line_request.py | 184 +++++++++++++--------------
bindings/python/tests/tests_line_settings.py | 12 +-
bindings/python/tests/tests_module.py | 20 +--
10 files changed, 200 insertions(+), 198 deletions(-)
diff --git a/bindings/python/tests/helpers.py b/bindings/python/tests/helpers.py
index f9a15e8e33f62ad63923bddedc206022eabe96b4..d327da2816594655cec5a76e024e31ff978d5d93 100644
--- a/bindings/python/tests/helpers.py
+++ b/bindings/python/tests/helpers.py
@@ -5,12 +5,12 @@ import os
class LinkGuard:
- def __init__(self, src, dst):
+ def __init__(self, src: str, dst: str) -> None:
self.src = src
self.dst = dst
- def __enter__(self):
+ def __enter__(self) -> None:
os.symlink(self.src, self.dst)
- def __exit__(self, type, val, tb):
+ def __exit__(self, type, val, tb) -> None: # type: ignore[no-untyped-def]
os.unlink(self.dst)
diff --git a/bindings/python/tests/tests_chip.py b/bindings/python/tests/tests_chip.py
index 9110bebf3596557fbacb3c7620e931982f9dc957..9c8f87579469e684ed3b6a5dbcef35e0856127ba 100644
--- a/bindings/python/tests/tests_chip.py
+++ b/bindings/python/tests/tests_chip.py
@@ -12,19 +12,19 @@ from .helpers import LinkGuard
class ChipConstructor(TestCase):
- def test_open_existing_chip(self):
+ def test_open_existing_chip(self) -> None:
sim = gpiosim.Chip()
with gpiod.Chip(sim.dev_path):
pass
- def test_open_existing_chip_with_keyword(self):
+ def test_open_existing_chip_with_keyword(self) -> None:
sim = gpiosim.Chip()
with gpiod.Chip(path=sim.dev_path):
pass
- def test_open_chip_by_link(self):
+ def test_open_chip_by_link(self) -> None:
link = "/tmp/gpiod-py-test-link.{}".format(os.getpid())
sim = gpiosim.Chip()
@@ -32,35 +32,35 @@ class ChipConstructor(TestCase):
with gpiod.Chip(link):
pass
- def test_open_nonexistent_chip(self):
+ def test_open_nonexistent_chip(self) -> None:
with self.assertRaises(OSError) as ex:
gpiod.Chip("/dev/nonexistent")
self.assertEqual(ex.exception.errno, errno.ENOENT)
- def test_open_not_a_character_device(self):
+ def test_open_not_a_character_device(self) -> None:
with self.assertRaises(OSError) as ex:
gpiod.Chip("/tmp")
self.assertEqual(ex.exception.errno, errno.ENOTTY)
- def test_open_not_a_gpio_device(self):
+ def test_open_not_a_gpio_device(self) -> None:
with self.assertRaises(OSError) as ex:
gpiod.Chip("/dev/null")
self.assertEqual(ex.exception.errno, errno.ENODEV)
- def test_missing_path(self):
+ def test_missing_path(self) -> None:
with self.assertRaises(TypeError):
gpiod.Chip()
- def test_invalid_type_for_path(self):
+ def test_invalid_type_for_path(self) -> None:
with self.assertRaises(TypeError):
gpiod.Chip(4)
class ChipBooleanConversion(TestCase):
- def test_chip_bool(self):
+ def test_chip_bool(self) -> None:
sim = gpiosim.Chip()
chip = gpiod.Chip(sim.dev_path)
self.assertTrue(chip)
@@ -69,21 +69,21 @@ class ChipBooleanConversion(TestCase):
class ChipProperties(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip()
self.chip = gpiod.Chip(self.sim.dev_path)
- def tearDown(self):
+ def tearDown(self) -> None:
self.chip.close()
self.sim = None
- def test_get_chip_path(self):
+ def test_get_chip_path(self) -> None:
self.assertEqual(self.sim.dev_path, self.chip.path)
- def test_get_fd(self):
+ def test_get_fd(self) -> None:
self.assertGreaterEqual(self.chip.fd, 0)
- def test_properties_are_immutable(self):
+ def test_properties_are_immutable(self) -> None:
with self.assertRaises(AttributeError):
self.chip.path = "foobar"
@@ -92,7 +92,7 @@ class ChipProperties(TestCase):
class ChipDevPathFromLink(TestCase):
- def test_dev_path_open_by_link(self):
+ def test_dev_path_open_by_link(self) -> None:
sim = gpiosim.Chip()
link = "/tmp/gpiod-py-test-link.{}".format(os.getpid())
@@ -102,7 +102,7 @@ class ChipDevPathFromLink(TestCase):
class ChipMapLine(TestCase):
- def test_lookup_by_name_good(self):
+ def test_lookup_by_name_good(self) -> None:
sim = gpiosim.Chip(
num_lines=8, line_names={1: "foo", 2: "bar", 4: "baz", 5: "xyz"}
)
@@ -110,7 +110,7 @@ class ChipMapLine(TestCase):
with gpiod.Chip(sim.dev_path) as chip:
self.assertEqual(chip.line_offset_from_id("baz"), 4)
- def test_lookup_by_name_good_keyword_argument(self):
+ def test_lookup_by_name_good_keyword_argument(self) -> None:
sim = gpiosim.Chip(
num_lines=8, line_names={1: "foo", 2: "bar", 4: "baz", 5: "xyz"}
)
@@ -118,7 +118,7 @@ class ChipMapLine(TestCase):
with gpiod.Chip(sim.dev_path) as chip:
self.assertEqual(chip.line_offset_from_id(id="baz"), 4)
- def test_lookup_bad_name(self):
+ def test_lookup_bad_name(self) -> None:
sim = gpiosim.Chip(
num_lines=8, line_names={1: "foo", 2: "bar", 4: "baz", 5: "xyz"}
)
@@ -127,21 +127,21 @@ class ChipMapLine(TestCase):
with self.assertRaises(FileNotFoundError):
chip.line_offset_from_id("nonexistent")
- def test_lookup_bad_offset(self):
+ def test_lookup_bad_offset(self) -> None:
sim = gpiosim.Chip()
with gpiod.Chip(sim.dev_path) as chip:
with self.assertRaises(ValueError):
chip.line_offset_from_id(4)
- def test_lookup_bad_offset_as_string(self):
+ def test_lookup_bad_offset_as_string(self) -> None:
sim = gpiosim.Chip()
with gpiod.Chip(sim.dev_path) as chip:
with self.assertRaises(ValueError):
chip.line_offset_from_id("4")
- def test_duplicate_names(self):
+ def test_duplicate_names(self) -> None:
sim = gpiosim.Chip(
num_lines=8, line_names={1: "foo", 2: "bar", 4: "baz", 5: "bar"}
)
@@ -149,14 +149,14 @@ class ChipMapLine(TestCase):
with gpiod.Chip(sim.dev_path) as chip:
self.assertEqual(chip.line_offset_from_id("bar"), 2)
- def test_integer_offsets(self):
+ def test_integer_offsets(self) -> None:
sim = gpiosim.Chip(num_lines=8, line_names={1: "foo", 2: "bar", 6: "baz"})
with gpiod.Chip(sim.dev_path) as chip:
self.assertEqual(chip.line_offset_from_id(4), 4)
self.assertEqual(chip.line_offset_from_id(1), 1)
- def test_offsets_as_string(self):
+ def test_offsets_as_string(self) -> None:
sim = gpiosim.Chip(num_lines=8, line_names={1: "foo", 2: "bar", 7: "6"})
with gpiod.Chip(sim.dev_path) as chip:
@@ -165,7 +165,7 @@ class ChipMapLine(TestCase):
class ClosedChipCannotBeUsed(TestCase):
- def test_close_chip_and_try_to_use_it(self):
+ def test_close_chip_and_try_to_use_it(self) -> None:
sim = gpiosim.Chip(label="foobar")
chip = gpiod.Chip(sim.dev_path)
@@ -174,7 +174,7 @@ class ClosedChipCannotBeUsed(TestCase):
with self.assertRaises(gpiod.ChipClosedError):
chip.path
- def test_close_chip_and_try_controlled_execution(self):
+ def test_close_chip_and_try_controlled_execution(self) -> None:
sim = gpiosim.Chip()
chip = gpiod.Chip(sim.dev_path)
@@ -184,7 +184,7 @@ class ClosedChipCannotBeUsed(TestCase):
with chip:
chip.fd
- def test_close_chip_twice(self):
+ def test_close_chip_twice(self) -> None:
sim = gpiosim.Chip(label="foobar")
chip = gpiod.Chip(sim.dev_path)
chip.close()
@@ -194,21 +194,21 @@ class ClosedChipCannotBeUsed(TestCase):
class StringRepresentation(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(num_lines=4, label="foobar")
self.chip = gpiod.Chip(self.sim.dev_path)
- def tearDown(self):
+ def tearDown(self) -> None:
self.chip.close()
self.sim = None
- def test_repr(self):
+ def test_repr(self) -> None:
self.assertEqual(repr(self.chip), 'gpiod.Chip("{}")'.format(self.sim.dev_path))
cmp = eval(repr(self.chip))
self.assertEqual(self.chip.path, cmp.path)
- def test_str(self):
+ def test_str(self) -> None:
info = self.chip.get_info()
self.assertEqual(
str(self.chip),
@@ -219,17 +219,17 @@ class StringRepresentation(TestCase):
class StringRepresentationClosed(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(num_lines=4, label="foobar")
self.chip = gpiod.Chip(self.sim.dev_path)
- def tearDown(self):
+ def tearDown(self) -> None:
self.sim = None
- def test_repr_closed(self):
+ def test_repr_closed(self) -> None:
self.chip.close()
self.assertEqual(repr(self.chip), "<Chip CLOSED>")
- def test_str_closed(self):
+ def test_str_closed(self) -> None:
self.chip.close()
self.assertEqual(str(self.chip), "<Chip CLOSED>")
diff --git a/bindings/python/tests/tests_chip_info.py b/bindings/python/tests/tests_chip_info.py
index 9474f38be3d33e60529e0e24fb4f10cb99ce9d5c..acb0da9d1f302186a2a6bca3e2f5a46abd3ebc51 100644
--- a/bindings/python/tests/tests_chip_info.py
+++ b/bindings/python/tests/tests_chip_info.py
@@ -9,27 +9,27 @@ from . import gpiosim
class ChipInfoProperties(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(label="foobar", num_lines=16)
self.chip = gpiod.Chip(self.sim.dev_path)
self.info = self.chip.get_info()
- def tearDown(self):
+ def tearDown(self) -> None:
self.info = None
self.chip.close()
self.chip = None
self.sim = None
- def test_chip_info_name(self):
+ def test_chip_info_name(self) -> None:
self.assertEqual(self.info.name, self.sim.name)
- def test_chip_info_label(self):
+ def test_chip_info_label(self) -> None:
self.assertEqual(self.info.label, "foobar")
- def test_chip_info_num_lines(self):
+ def test_chip_info_num_lines(self) -> None:
self.assertEqual(self.info.num_lines, 16)
- def test_chip_info_properties_are_immutable(self):
+ def test_chip_info_properties_are_immutable(self) -> None:
with self.assertRaises(AttributeError):
self.info.name = "foobar"
@@ -41,7 +41,7 @@ class ChipInfoProperties(TestCase):
class ChipInfoStringRepresentation(TestCase):
- def test_chip_info_str(self):
+ def test_chip_info_str(self) -> None:
sim = gpiosim.Chip(label="foobar", num_lines=16)
with gpiod.Chip(sim.dev_path) as chip:
diff --git a/bindings/python/tests/tests_edge_event.py b/bindings/python/tests/tests_edge_event.py
index c24d344fdbd6a1b9eda9497afab8a61c5ecb8f09..f80d6a52680c48405b935fca8e47e2a2817a2fac 100644
--- a/bindings/python/tests/tests_edge_event.py
+++ b/bindings/python/tests/tests_edge_event.py
@@ -17,7 +17,7 @@ Pull = gpiosim.Chip.Pull
class EdgeEventWaitTimeout(TestCase):
- def test_event_wait_timeout(self):
+ def test_event_wait_timeout(self) -> None:
sim = gpiosim.Chip()
with gpiod.request_lines(
@@ -26,7 +26,7 @@ class EdgeEventWaitTimeout(TestCase):
) as req:
self.assertEqual(req.wait_edge_events(timedelta(microseconds=10000)), False)
- def test_event_wait_timeout_float(self):
+ def test_event_wait_timeout_float(self) -> None:
sim = gpiosim.Chip()
with gpiod.request_lines(
@@ -37,7 +37,7 @@ class EdgeEventWaitTimeout(TestCase):
class EdgeEventInvalidConfig(TestCase):
- def test_output_mode_and_edge_detection(self):
+ def test_output_mode_and_edge_detection(self) -> None:
sim = gpiosim.Chip()
with self.assertRaises(ValueError):
@@ -52,29 +52,31 @@ class EdgeEventInvalidConfig(TestCase):
class WaitingForEdgeEvents(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(num_lines=8)
self.thread = None
- def tearDown(self):
+ def tearDown(self) -> None:
if self.thread:
self.thread.join()
del self.thread
self.sim = None
- def trigger_falling_and_rising_edge(self, offset):
+ def trigger_falling_and_rising_edge(self, offset: int) -> None:
time.sleep(0.05)
self.sim.set_pull(offset, Pull.UP)
time.sleep(0.05)
self.sim.set_pull(offset, Pull.DOWN)
- def trigger_rising_edge_events_on_two_offsets(self, offset0, offset1):
+ def trigger_rising_edge_events_on_two_offsets(
+ self, offset0: int, offset1: int
+ ) -> None:
time.sleep(0.05)
self.sim.set_pull(offset0, Pull.UP)
time.sleep(0.05)
self.sim.set_pull(offset1, Pull.UP)
- def test_both_edge_events(self):
+ def test_both_edge_events(self) -> None:
with gpiod.request_lines(
self.sim.dev_path, {2: gpiod.LineSettings(edge_detection=Edge.BOTH)}
) as req:
@@ -101,7 +103,7 @@ class WaitingForEdgeEvents(TestCase):
self.assertGreater(ts_falling, ts_rising)
- def test_rising_edge_event(self):
+ def test_rising_edge_event(self) -> None:
with gpiod.request_lines(
self.sim.dev_path, {6: gpiod.LineSettings(edge_detection=Edge.RISING)}
) as req:
@@ -119,7 +121,7 @@ class WaitingForEdgeEvents(TestCase):
self.assertFalse(req.wait_edge_events(timedelta(microseconds=10000)))
- def test_falling_edge_event(self):
+ def test_falling_edge_event(self) -> None:
with gpiod.request_lines(
self.sim.dev_path, {6: gpiod.LineSettings(edge_detection=Edge.FALLING)}
) as req:
@@ -137,7 +139,7 @@ class WaitingForEdgeEvents(TestCase):
self.assertFalse(req.wait_edge_events(timedelta(microseconds=10000)))
- def test_sequence_numbers(self):
+ def test_sequence_numbers(self) -> None:
with gpiod.request_lines(
self.sim.dev_path, {(2, 4): gpiod.LineSettings(edge_detection=Edge.BOTH)}
) as req:
@@ -166,7 +168,7 @@ class WaitingForEdgeEvents(TestCase):
class ReadingMultipleEdgeEvents(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(num_lines=8)
self.request = gpiod.request_lines(
self.sim.dev_path, {1: gpiod.LineSettings(edge_detection=Edge.BOTH)}
@@ -180,12 +182,12 @@ class ReadingMultipleEdgeEvents(TestCase):
self.sim.set_pull(1, Pull.UP)
time.sleep(0.05)
- def tearDown(self):
+ def tearDown(self) -> None:
self.request.release()
del self.request
del self.sim
- def test_read_multiple_events(self):
+ def test_read_multiple_events(self) -> None:
self.assertTrue(self.request.wait_edge_events(timedelta(seconds=1)))
events = self.request.read_edge_events()
self.assertEqual(len(events), 3)
@@ -199,7 +201,7 @@ class ReadingMultipleEdgeEvents(TestCase):
class EdgeEventStringRepresentation(TestCase):
- def test_edge_event_str(self):
+ def test_edge_event_str(self) -> None:
sim = gpiosim.Chip()
with gpiod.request_lines(
diff --git a/bindings/python/tests/tests_info_event.py b/bindings/python/tests/tests_info_event.py
index 1976f4be8b9a63942275875ada00472402524350..7e12b8e33f1a425423a1b2f30dd5af9a331906e9 100644
--- a/bindings/python/tests/tests_info_event.py
+++ b/bindings/python/tests/tests_info_event.py
@@ -18,7 +18,7 @@ _EventType = gpiod.InfoEvent.Type
class InfoEventDataclassBehavior(TestCase):
- def test_info_event_props_are_frozen(self):
+ def test_info_event_props_are_frozen(self) -> None:
sim = gpiosim.Chip()
with gpiod.Chip(sim.dev_path) as chip:
@@ -37,7 +37,7 @@ class InfoEventDataclassBehavior(TestCase):
event.line_info = 4
-def request_reconfigure_release_line(chip_path, offset):
+def request_reconfigure_release_line(chip_path: str, offset: int) -> None:
time.sleep(0.1)
with gpiod.request_lines(chip_path, config={offset: None}) as request:
time.sleep(0.1)
@@ -48,12 +48,12 @@ def request_reconfigure_release_line(chip_path, offset):
class WatchingInfoEventWorks(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(num_lines=8, line_names={4: "foobar"})
self.chip = gpiod.Chip(self.sim.dev_path)
self.thread = None
- def tearDown(self):
+ def tearDown(self) -> None:
if self.thread:
self.thread.join()
self.thread = None
@@ -62,35 +62,35 @@ class WatchingInfoEventWorks(TestCase):
self.chip = None
self.sim = None
- def test_watch_line_info_returns_line_info(self):
+ def test_watch_line_info_returns_line_info(self) -> None:
info = self.chip.watch_line_info(7)
self.assertEqual(info.offset, 7)
- def test_watch_line_info_keyword_argument(self):
+ def test_watch_line_info_keyword_argument(self) -> None:
info = self.chip.watch_line_info(line=7)
- def test_watch_line_info_offset_out_of_range(self):
+ def test_watch_line_info_offset_out_of_range(self) -> None:
with self.assertRaises(ValueError):
self.chip.watch_line_info(8)
- def test_watch_line_info_no_arguments(self):
+ def test_watch_line_info_no_arguments(self) -> None:
with self.assertRaises(TypeError):
self.chip.watch_line_info()
- def test_watch_line_info_by_line_name(self):
+ def test_watch_line_info_by_line_name(self) -> None:
self.chip.watch_line_info("foobar")
- def test_watch_line_info_invalid_argument_type(self):
+ def test_watch_line_info_invalid_argument_type(self) -> None:
with self.assertRaises(TypeError):
self.chip.watch_line_info(None)
- def test_wait_for_event_timeout(self):
+ def test_wait_for_event_timeout(self) -> None:
info = self.chip.watch_line_info(7)
self.assertFalse(
self.chip.wait_info_event(datetime.timedelta(microseconds=10000))
)
- def test_request_reconfigure_release_events(self):
+ def test_request_reconfigure_release_events(self) -> None:
info = self.chip.watch_line_info(7)
self.assertEqual(info.direction, Direction.INPUT)
@@ -132,16 +132,16 @@ class WatchingInfoEventWorks(TestCase):
class UnwatchingLineInfo(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(num_lines=8, line_names={4: "foobar"})
self.chip = gpiod.Chip(self.sim.dev_path)
- def tearDown(self):
+ def tearDown(self) -> None:
self.chip.close()
self.chip = None
self.sim = None
- def test_unwatch_line_info(self):
+ def test_unwatch_line_info(self) -> None:
self.chip.watch_line_info(0)
with self.chip.request_lines(config={0: None}) as request:
self.assertTrue(self.chip.wait_info_event(datetime.timedelta(seconds=1)))
@@ -153,17 +153,17 @@ class UnwatchingLineInfo(TestCase):
self.chip.wait_info_event(datetime.timedelta(microseconds=10000))
)
- def test_unwatch_not_watched_line(self):
+ def test_unwatch_not_watched_line(self) -> None:
with self.assertRaises(OSError) as ex:
self.chip.unwatch_line_info(2)
self.assertEqual(ex.exception.errno, errno.EBUSY)
- def test_unwatch_line_info_no_argument(self):
+ def test_unwatch_line_info_no_argument(self) -> None:
with self.assertRaises(TypeError):
self.chip.unwatch_line_info()
- def test_unwatch_line_info_by_line_name(self):
+ def test_unwatch_line_info_by_line_name(self) -> None:
self.chip.watch_line_info(4)
with self.chip.request_lines(config={4: None}) as request:
self.assertIsNotNone(self.chip.read_info_event())
@@ -175,7 +175,7 @@ class UnwatchingLineInfo(TestCase):
class InfoEventStringRepresentation(TestCase):
- def test_info_event_str(self):
+ def test_info_event_str(self) -> None:
sim = gpiosim.Chip()
with gpiod.Chip(sim.dev_path) as chip:
diff --git a/bindings/python/tests/tests_line.py b/bindings/python/tests/tests_line.py
index 218256711b2b248f692f07b9ae99e462f03c6965..c96f6de87fe811663b6040f27fee354fd203dcbc 100644
--- a/bindings/python/tests/tests_line.py
+++ b/bindings/python/tests/tests_line.py
@@ -7,6 +7,6 @@ from gpiod.line import Value
class LineValue(TestCase):
- def test_cast_bool(self):
+ def test_cast_bool(self) -> None:
self.assertTrue(bool(Value.ACTIVE))
self.assertFalse(bool(Value.INACTIVE))
diff --git a/bindings/python/tests/tests_line_info.py b/bindings/python/tests/tests_line_info.py
index 79281a82932a32bdb8c89f2aac7b15eb28eafd9d..9828349810eed0e3fa755f8557ec314d3e86ed7a 100644
--- a/bindings/python/tests/tests_line_info.py
+++ b/bindings/python/tests/tests_line_info.py
@@ -12,7 +12,7 @@ HogDir = gpiosim.Chip.Direction
class GetLineInfo(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(
num_lines=4,
line_names={0: "foobar"},
@@ -20,37 +20,37 @@ class GetLineInfo(TestCase):
self.chip = gpiod.Chip(self.sim.dev_path)
- def tearDown(self):
+ def tearDown(self) -> None:
self.chip.close()
self.chip = None
self.sim = None
- def test_get_line_info_by_offset(self):
+ def test_get_line_info_by_offset(self) -> None:
self.chip.get_line_info(0)
- def test_get_line_info_by_offset_keyword(self):
+ def test_get_line_info_by_offset_keyword(self) -> None:
self.chip.get_line_info(line=0)
- def test_get_line_info_by_name(self):
+ def test_get_line_info_by_name(self) -> None:
self.chip.get_line_info("foobar")
- def test_get_line_info_by_name_keyword(self):
+ def test_get_line_info_by_name_keyword(self) -> None:
self.chip.get_line_info(line="foobar")
- def test_get_line_info_by_offset_string(self):
+ def test_get_line_info_by_offset_string(self) -> None:
self.chip.get_line_info("2")
- def test_offset_out_of_range(self):
+ def test_offset_out_of_range(self) -> None:
with self.assertRaises(ValueError) as ex:
self.chip.get_line_info(4)
- def test_no_offset(self):
+ def test_no_offset(self) -> None:
with self.assertRaises(TypeError):
self.chip.get_line_info()
class LinePropertiesCanBeRead(TestCase):
- def test_basic_properties(self):
+ def test_basic_properties(self) -> None:
sim = gpiosim.Chip(
num_lines=8,
line_names={1: "foo", 2: "bar", 4: "baz", 5: "xyz"},
@@ -87,7 +87,7 @@ class LinePropertiesCanBeRead(TestCase):
class LineInfoStringRepresentation(TestCase):
- def test_line_info_str(self):
+ def test_line_info_str(self) -> None:
sim = gpiosim.Chip(
line_names={0: "foo"}, hogs={0: ("hogger", HogDir.OUTPUT_HIGH)}
)
diff --git a/bindings/python/tests/tests_line_request.py b/bindings/python/tests/tests_line_request.py
index c3e86c56be63f7e449c07e7833cb7080ee42b0ac..76edb1d273f103c1b2f72974f5364728f121b05b 100644
--- a/bindings/python/tests/tests_line_request.py
+++ b/bindings/python/tests/tests_line_request.py
@@ -13,78 +13,78 @@ SimVal = gpiosim.Chip.Value
class ChipLineRequestsBehaveCorrectlyWithInvalidArguments(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(num_lines=8)
self.chip = gpiod.Chip(self.sim.dev_path)
- def tearDown(self):
+ def tearDown(self) -> None:
self.chip.close()
del self.chip
del self.sim
- def test_passing_invalid_types_as_configs(self):
+ def test_passing_invalid_types_as_configs(self) -> None:
with self.assertRaises(AttributeError):
self.chip.request_lines("foobar")
with self.assertRaises(AttributeError):
self.chip.request_lines(None, "foobar")
- def test_offset_out_of_range(self):
+ def test_offset_out_of_range(self) -> None:
with self.assertRaises(ValueError):
self.chip.request_lines(config={(1, 0, 4, 8): None})
- def test_line_name_not_found(self):
+ def test_line_name_not_found(self) -> None:
with self.assertRaises(FileNotFoundError):
self.chip.request_lines(config={"foo": None})
- def test_request_no_arguments(self):
+ def test_request_no_arguments(self) -> None:
with self.assertRaises(TypeError):
self.chip.request_lines()
class ModuleLineRequestsBehaveCorrectlyWithInvalidArguments(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(num_lines=8)
- def tearDown(self):
+ def tearDown(self) -> None:
del self.sim
- def test_passing_invalid_types_as_configs(self):
+ def test_passing_invalid_types_as_configs(self) -> None:
with self.assertRaises(AttributeError):
gpiod.request_lines(self.sim.dev_path, "foobar")
with self.assertRaises(AttributeError):
gpiod.request_lines(self.sim.dev_path, None, "foobar")
- def test_offset_out_of_range(self):
+ def test_offset_out_of_range(self) -> None:
with self.assertRaises(ValueError):
gpiod.request_lines(self.sim.dev_path, config={(1, 0, 4, 8): None})
- def test_line_name_not_found(self):
+ def test_line_name_not_found(self) -> None:
with self.assertRaises(FileNotFoundError):
gpiod.request_lines(self.sim.dev_path, config={"foo": None})
- def test_request_no_arguments(self):
+ def test_request_no_arguments(self) -> None:
with self.assertRaises(TypeError):
gpiod.request_lines()
class ChipLineRequestWorks(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(num_lines=8, line_names={5: "foo", 7: "bar"})
self.chip = gpiod.Chip(self.sim.dev_path)
- def tearDown(self):
+ def tearDown(self) -> None:
self.chip.close()
del self.chip
del self.sim
- def test_request_with_positional_arguments(self):
+ def test_request_with_positional_arguments(self) -> None:
with self.chip.request_lines({(0, 5, 3, 1): None}, "foobar", 32) as req:
self.assertEqual(req.offsets, [0, 5, 3, 1])
self.assertEqual(self.chip.get_line_info(0).consumer, "foobar")
- def test_request_with_keyword_arguments(self):
+ def test_request_with_keyword_arguments(self) -> None:
with self.chip.request_lines(
config={(0, 5, 6): None},
consumer="foobar",
@@ -93,31 +93,31 @@ class ChipLineRequestWorks(TestCase):
self.assertEqual(req.offsets, [0, 5, 6])
self.assertEqual(self.chip.get_line_info(0).consumer, "foobar")
- def test_request_single_offset_as_int(self):
+ def test_request_single_offset_as_int(self) -> None:
with self.chip.request_lines(config={4: None}) as req:
self.assertEqual(req.offsets, [4])
- def test_request_single_offset_as_tuple(self):
+ def test_request_single_offset_as_tuple(self) -> None:
with self.chip.request_lines(config={(4): None}) as req:
self.assertEqual(req.offsets, [4])
- def test_request_by_name(self):
+ 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])
- def test_request_single_line_by_name(self):
+ def test_request_single_line_by_name(self) -> None:
with self.chip.request_lines(config={"foo": None}) as req:
self.assertEqual(req.offsets, [5])
class ModuleLineRequestWorks(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(num_lines=8, line_names={5: "foo", 7: "bar"})
- def tearDown(self):
+ def tearDown(self) -> None:
del self.sim
- def test_request_with_positional_arguments(self):
+ def test_request_with_positional_arguments(self) -> None:
with gpiod.request_lines(
self.sim.dev_path, {(0, 5, 3, 1): None}, "foobar", 32
) as req:
@@ -125,7 +125,7 @@ class ModuleLineRequestWorks(TestCase):
with gpiod.Chip(self.sim.dev_path) as chip:
self.assertEqual(chip.get_line_info(5).consumer, "foobar")
- def test_request_with_keyword_arguments(self):
+ def test_request_with_keyword_arguments(self) -> None:
with gpiod.request_lines(
path=self.sim.dev_path,
config={(0, 5, 6): None},
@@ -136,15 +136,15 @@ class ModuleLineRequestWorks(TestCase):
with gpiod.Chip(self.sim.dev_path) as chip:
self.assertEqual(chip.get_line_info(5).consumer, "foobar")
- def test_request_single_offset_as_int(self):
+ def test_request_single_offset_as_int(self) -> None:
with gpiod.request_lines(path=self.sim.dev_path, config={4: None}) as req:
self.assertEqual(req.offsets, [4])
- def test_request_single_offset_as_tuple(self):
+ def test_request_single_offset_as_tuple(self) -> None:
with gpiod.request_lines(path=self.sim.dev_path, config={(4): None}) as req:
self.assertEqual(req.offsets, [4])
- def test_request_by_name(self):
+ def test_request_by_name(self) -> None:
with gpiod.request_lines(
self.sim.dev_path, {(1, 2, "foo", "bar"): None}
) as req:
@@ -152,29 +152,29 @@ class ModuleLineRequestWorks(TestCase):
class LineRequestGettingValues(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(num_lines=8)
self.req = gpiod.request_lines(
self.sim.dev_path,
{(0, 1, 2, 3): gpiod.LineSettings(direction=Direction.INPUT)},
)
- def tearDown(self):
+ def tearDown(self) -> None:
self.req.release()
del self.req
del self.sim
- def test_get_single_value(self):
+ def test_get_single_value(self) -> None:
self.sim.set_pull(1, Pull.UP)
self.assertEqual(self.req.get_values([1]), [Value.ACTIVE])
- def test_get_single_value_helper(self):
+ def test_get_single_value_helper(self) -> None:
self.sim.set_pull(1, Pull.UP)
self.assertEqual(self.req.get_value(1), Value.ACTIVE)
- def test_get_values_for_subset_of_lines(self):
+ def test_get_values_for_subset_of_lines(self) -> None:
self.sim.set_pull(0, Pull.UP)
self.sim.set_pull(1, Pull.DOWN)
self.sim.set_pull(3, Pull.UP)
@@ -183,7 +183,7 @@ class LineRequestGettingValues(TestCase):
self.req.get_values([0, 1, 3]), [Value.ACTIVE, Value.INACTIVE, Value.ACTIVE]
)
- def test_get_all_values(self):
+ def test_get_all_values(self) -> None:
self.sim.set_pull(0, Pull.DOWN)
self.sim.set_pull(1, Pull.UP)
self.sim.set_pull(2, Pull.UP)
@@ -194,29 +194,29 @@ class LineRequestGettingValues(TestCase):
[Value.INACTIVE, Value.ACTIVE, Value.ACTIVE, Value.ACTIVE],
)
- def test_get_values_invalid_offset(self):
+ def test_get_values_invalid_offset(self) -> None:
with self.assertRaises(ValueError):
self.req.get_values([9])
- def test_get_values_invalid_argument_type(self):
+ def test_get_values_invalid_argument_type(self) -> None:
with self.assertRaises(TypeError):
self.req.get_values(True)
class LineRequestGettingValuesByName(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(num_lines=4, line_names={2: "foo", 3: "bar", 1: "baz"})
self.req = gpiod.request_lines(
self.sim.dev_path,
{(0, "baz", "bar", "foo"): gpiod.LineSettings(direction=Direction.INPUT)},
)
- def tearDown(self):
+ def tearDown(self) -> None:
self.req.release()
del self.req
del self.sim
- def test_get_values_by_name(self):
+ def test_get_values_by_name(self) -> None:
self.sim.set_pull(1, Pull.UP)
self.sim.set_pull(2, Pull.DOWN)
self.sim.set_pull(3, Pull.UP)
@@ -226,58 +226,58 @@ class LineRequestGettingValuesByName(TestCase):
[Value.INACTIVE, Value.ACTIVE, Value.ACTIVE],
)
- def test_get_values_by_bad_name(self):
+ def test_get_values_by_bad_name(self) -> None:
with self.assertRaises(ValueError):
self.req.get_values(["xyz"])
class LineRequestSettingValues(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(num_lines=8)
self.req = gpiod.request_lines(
self.sim.dev_path,
{(0, 1, 2, 3): gpiod.LineSettings(direction=Direction.OUTPUT)},
)
- def tearDown(self):
+ def tearDown(self) -> None:
self.req.release()
del self.req
del self.sim
- def test_set_single_value(self):
+ def test_set_single_value(self) -> None:
self.req.set_values({1: Value.ACTIVE})
self.assertEqual(self.sim.get_value(1), SimVal.ACTIVE)
- def test_set_single_value_helper(self):
+ def test_set_single_value_helper(self) -> None:
self.req.set_value(1, Value.ACTIVE)
self.assertEqual(self.sim.get_value(1), SimVal.ACTIVE)
- def test_set_values_for_subset_of_lines(self):
+ def test_set_values_for_subset_of_lines(self) -> None:
self.req.set_values({0: Value.ACTIVE, 1: Value.INACTIVE, 3: Value.ACTIVE})
self.assertEqual(self.sim.get_value(0), SimVal.ACTIVE)
self.assertEqual(self.sim.get_value(1), SimVal.INACTIVE)
self.assertEqual(self.sim.get_value(3), SimVal.ACTIVE)
- def test_set_values_invalid_offset(self):
+ def test_set_values_invalid_offset(self) -> None:
with self.assertRaises(ValueError):
self.req.set_values({9: Value.ACTIVE})
class LineRequestSettingValuesByName(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(num_lines=4, line_names={2: "foo", 3: "bar", 1: "baz"})
self.req = gpiod.request_lines(
self.sim.dev_path,
{(0, "baz", "bar", "foo"): gpiod.LineSettings(direction=Direction.OUTPUT)},
)
- def tearDown(self):
+ def tearDown(self) -> None:
self.req.release()
del self.req
del self.sim
- def test_set_values_by_name(self):
+ def test_set_values_by_name(self) -> None:
self.req.set_values(
{"foo": Value.INACTIVE, "bar": Value.ACTIVE, 1: Value.ACTIVE}
)
@@ -286,13 +286,13 @@ class LineRequestSettingValuesByName(TestCase):
self.assertEqual(self.sim.get_value(1), SimVal.ACTIVE)
self.assertEqual(self.sim.get_value(3), SimVal.ACTIVE)
- def test_set_values_by_bad_name(self):
+ def test_set_values_by_bad_name(self) -> None:
with self.assertRaises(ValueError):
self.req.set_values({"xyz": Value.ACTIVE})
class LineRequestComplexConfig(TestCase):
- def test_complex_config(self):
+ def test_complex_config(self) -> None:
sim = gpiosim.Chip(num_lines=8)
with gpiod.Chip(sim.dev_path) as chip:
@@ -314,7 +314,7 @@ class LineRequestComplexConfig(TestCase):
class LineRequestMixedConfigByName(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(
num_lines=4, line_names={2: "foo", 3: "bar", 1: "baz", 0: "xyz"}
)
@@ -326,18 +326,18 @@ class LineRequestMixedConfigByName(TestCase):
},
)
- def tearDown(self):
+ def tearDown(self) -> None:
self.req.release()
del self.req
del self.sim
- def test_set_values_by_name(self):
+ def test_set_values_by_name(self) -> None:
self.req.set_values({"bar": Value.ACTIVE, "baz": Value.INACTIVE})
self.assertEqual(self.sim.get_value(1), SimVal.INACTIVE)
self.assertEqual(self.sim.get_value(3), SimVal.ACTIVE)
- def test_get_values_by_name(self):
+ def test_get_values_by_name(self) -> None:
self.sim.set_pull(0, Pull.UP)
self.sim.set_pull(2, Pull.DOWN)
@@ -348,40 +348,40 @@ class LineRequestMixedConfigByName(TestCase):
class RepeatingLinesInRequestConfig(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(num_lines=4, line_names={0: "foo", 2: "bar"})
self.chip = gpiod.Chip(self.sim.dev_path)
- def tearDown(self):
+ def tearDown(self) -> None:
self.chip.close()
del self.chip
del self.sim
- def test_offsets_repeating_within_the_same_tuple(self):
+ def test_offsets_repeating_within_the_same_tuple(self) -> None:
with self.assertRaises(ValueError):
self.chip.request_lines({(0, 1, 2, 1): None})
- def test_offsets_repeating_in_different_tuples(self):
+ def test_offsets_repeating_in_different_tuples(self) -> None:
with self.assertRaises(ValueError):
self.chip.request_lines({(0, 1, 2): None, (3, 4, 0): None})
- def test_offset_and_name_conflict_in_the_same_tuple(self):
+ def test_offset_and_name_conflict_in_the_same_tuple(self) -> None:
with self.assertRaises(ValueError):
self.chip.request_lines({(2, "bar"): None})
- def test_offset_and_name_conflict_in_different_tuples(self):
+ def test_offset_and_name_conflict_in_different_tuples(self) -> None:
with self.assertRaises(ValueError):
self.chip.request_lines({(0, 1, 2): None, (4, 5, "bar"): None})
class LineRequestPropertiesWork(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(num_lines=16, line_names={0: "foo", 2: "bar", 5: "baz"})
- def tearDown(self):
+ def tearDown(self) -> None:
del self.sim
- def test_property_fd(self):
+ def test_property_fd(self) -> None:
with gpiod.request_lines(
self.sim.dev_path,
config={
@@ -392,19 +392,19 @@ class LineRequestPropertiesWork(TestCase):
) as req:
self.assertGreaterEqual(req.fd, 0)
- def test_property_num_lines(self):
+ def test_property_num_lines(self) -> None:
with gpiod.request_lines(
self.sim.dev_path, config={(0, 2, 3, 5, 6, 8, 12): None}
) as req:
self.assertEqual(req.num_lines, 7)
- def test_property_offsets(self):
+ def test_property_offsets(self) -> None:
with gpiod.request_lines(
self.sim.dev_path, config={(1, 6, 12, 4): None}
) as req:
self.assertEqual(req.offsets, [1, 6, 12, 4])
- def test_property_lines(self):
+ def test_property_lines(self) -> None:
with gpiod.request_lines(
self.sim.dev_path, config={("foo", 1, "bar", 4, "baz"): None}
) as req:
@@ -412,43 +412,43 @@ class LineRequestPropertiesWork(TestCase):
class LineRequestConsumerString(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(num_lines=4)
self.chip = gpiod.Chip(self.sim.dev_path)
- def tearDown(self):
+ def tearDown(self) -> None:
self.chip.close()
del self.chip
del self.sim
- def test_custom_consumer(self):
+ def test_custom_consumer(self) -> None:
with self.chip.request_lines(
consumer="foobar", config={(2, 3): None}
) as request:
info = self.chip.get_line_info(2)
self.assertEqual(info.consumer, "foobar")
- def test_empty_consumer(self):
+ def test_empty_consumer(self) -> None:
with self.chip.request_lines(consumer="", config={(2, 3): None}) as request:
info = self.chip.get_line_info(2)
self.assertEqual(info.consumer, "?")
- def test_default_consumer(self):
+ def test_default_consumer(self) -> None:
with self.chip.request_lines(config={(2, 3): None}) as request:
info = self.chip.get_line_info(2)
self.assertEqual(info.consumer, "?")
class LineRequestSetOutputValues(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(
num_lines=4, line_names={0: "foo", 1: "bar", 2: "baz", 3: "xyz"}
)
- def tearDown(self):
+ def tearDown(self) -> None:
del self.sim
- def test_request_with_globally_set_output_values(self):
+ def test_request_with_globally_set_output_values(self) -> None:
with gpiod.request_lines(
self.sim.dev_path,
config={(0, 1, 2, 3): gpiod.LineSettings(direction=Direction.OUTPUT)},
@@ -464,7 +464,7 @@ class LineRequestSetOutputValues(TestCase):
self.assertEqual(self.sim.get_value(2), SimVal.ACTIVE)
self.assertEqual(self.sim.get_value(3), SimVal.INACTIVE)
- def test_request_with_globally_set_output_values_with_mapping(self):
+ def test_request_with_globally_set_output_values_with_mapping(self) -> None:
with gpiod.request_lines(
self.sim.dev_path,
config={(0, 1, 2, 3): gpiod.LineSettings(direction=Direction.OUTPUT)},
@@ -475,7 +475,7 @@ class LineRequestSetOutputValues(TestCase):
self.assertEqual(self.sim.get_value(2), SimVal.ACTIVE)
self.assertEqual(self.sim.get_value(3), SimVal.INACTIVE)
- def test_request_with_globally_set_output_values_bad_mapping(self):
+ def test_request_with_globally_set_output_values_bad_mapping(self) -> None:
with self.assertRaises(FileNotFoundError):
with gpiod.request_lines(
self.sim.dev_path,
@@ -484,7 +484,7 @@ class LineRequestSetOutputValues(TestCase):
) as request:
pass
- def test_request_with_globally_set_output_values_bad_offset(self):
+ def test_request_with_globally_set_output_values_bad_offset(self) -> None:
with self.assertRaises(ValueError):
with gpiod.request_lines(
self.sim.dev_path,
@@ -495,7 +495,7 @@ class LineRequestSetOutputValues(TestCase):
class ReconfigureRequestedLines(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(num_lines=8, line_names={3: "foo", 4: "bar", 6: "baz"})
self.chip = gpiod.Chip(self.sim.dev_path)
self.req = self.chip.request_lines(
@@ -506,14 +506,14 @@ class ReconfigureRequestedLines(TestCase):
}
)
- def tearDown(self):
+ def tearDown(self) -> None:
self.chip.close()
del self.chip
self.req.release()
del self.req
del self.sim
- def test_reconfigure_by_offsets(self):
+ def test_reconfigure_by_offsets(self) -> None:
info = self.chip.get_line_info(2)
self.assertEqual(info.direction, Direction.OUTPUT)
self.req.reconfigure_lines(
@@ -522,7 +522,7 @@ class ReconfigureRequestedLines(TestCase):
info = self.chip.get_line_info(2)
self.assertEqual(info.direction, Direction.INPUT)
- def test_reconfigure_by_names(self):
+ def test_reconfigure_by_names(self) -> None:
info = self.chip.get_line_info(2)
self.assertEqual(info.direction, Direction.OUTPUT)
self.req.reconfigure_lines(
@@ -531,7 +531,7 @@ class ReconfigureRequestedLines(TestCase):
info = self.chip.get_line_info(2)
self.assertEqual(info.direction, Direction.INPUT)
- def test_reconfigure_by_misordered_offsets(self):
+ def test_reconfigure_by_misordered_offsets(self) -> None:
info = self.chip.get_line_info(2)
self.assertEqual(info.direction, Direction.OUTPUT)
self.req.reconfigure_lines(
@@ -540,7 +540,7 @@ class ReconfigureRequestedLines(TestCase):
info = self.chip.get_line_info(2)
self.assertEqual(info.direction, Direction.INPUT)
- def test_reconfigure_by_misordered_names(self):
+ def test_reconfigure_by_misordered_names(self) -> None:
info = self.chip.get_line_info(2)
self.assertEqual(info.direction, Direction.OUTPUT)
self.req.reconfigure_lines(
@@ -549,7 +549,7 @@ class ReconfigureRequestedLines(TestCase):
info = self.chip.get_line_info(2)
self.assertEqual(info.direction, Direction.INPUT)
- def test_reconfigure_with_default(self):
+ def test_reconfigure_with_default(self) -> None:
info = self.chip.get_line_info(2)
self.assertEqual(info.direction, Direction.OUTPUT)
self.assertTrue(info.active_low)
@@ -568,7 +568,7 @@ class ReconfigureRequestedLines(TestCase):
self.assertTrue(info.active_low)
self.assertEqual(info.drive, Drive.OPEN_DRAIN)
- def test_reconfigure_missing_offsets(self):
+ def test_reconfigure_missing_offsets(self) -> None:
info = self.chip.get_line_info(2)
self.assertEqual(info.direction, Direction.OUTPUT)
self.assertTrue(info.active_low)
@@ -583,7 +583,7 @@ class ReconfigureRequestedLines(TestCase):
self.assertTrue(info.active_low)
self.assertEqual(info.drive, Drive.OPEN_DRAIN)
- def test_reconfigure_extra_offsets(self):
+ def test_reconfigure_extra_offsets(self) -> None:
info = self.chip.get_line_info(2)
self.assertEqual(info.direction, Direction.OUTPUT)
self.req.reconfigure_lines(
@@ -594,7 +594,7 @@ class ReconfigureRequestedLines(TestCase):
class ReleasedLineRequestCannotBeUsed(TestCase):
- def test_using_released_line_request(self):
+ def test_using_released_line_request(self) -> None:
sim = gpiosim.Chip()
with gpiod.Chip(sim.dev_path) as chip:
@@ -606,7 +606,7 @@ class ReleasedLineRequestCannotBeUsed(TestCase):
class LineRequestSurvivesParentChip(TestCase):
- def test_line_request_survives_parent_chip(self):
+ def test_line_request_survives_parent_chip(self) -> None:
sim = gpiosim.Chip()
chip = gpiod.Chip(sim.dev_path)
@@ -624,13 +624,13 @@ class LineRequestSurvivesParentChip(TestCase):
class LineRequestStringRepresentation(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.sim = gpiosim.Chip(num_lines=8)
- def tearDown(self):
+ def tearDown(self) -> None:
del self.sim
- def test_str(self):
+ def test_str(self) -> None:
with gpiod.Chip(self.sim.dev_path) as chip:
with chip.request_lines(config={(2, 6, 4, 1): None}) as req:
self.assertEqual(
@@ -640,7 +640,7 @@ class LineRequestStringRepresentation(TestCase):
),
)
- def test_str_released(self):
+ def test_str_released(self) -> None:
req = gpiod.request_lines(self.sim.dev_path, config={(2, 6, 4, 1): None})
req.release()
self.assertEqual(str(req), "<LineRequest RELEASED>")
diff --git a/bindings/python/tests/tests_line_settings.py b/bindings/python/tests/tests_line_settings.py
index 832ac8a2377ddb25f5a5ab5c1732d1a9d5c5dff1..66e01dfea3339391b2146cf3ed2c26c8fc1cc34e 100644
--- a/bindings/python/tests/tests_line_settings.py
+++ b/bindings/python/tests/tests_line_settings.py
@@ -9,7 +9,7 @@ from gpiod.line import Bias, Clock, Direction, Drive, Edge, Value
class LineSettingsConstructor(TestCase):
- def test_default_values(self):
+ def test_default_values(self) -> None:
settings = gpiod.LineSettings()
self.assertEqual(settings.direction, Direction.AS_IS)
@@ -21,7 +21,7 @@ class LineSettingsConstructor(TestCase):
self.assertEqual(settings.event_clock, Clock.MONOTONIC)
self.assertEqual(settings.output_value, Value.INACTIVE)
- def test_keyword_arguments(self):
+ def test_keyword_arguments(self) -> None:
settings = gpiod.LineSettings(
direction=Direction.INPUT,
edge_detection=Edge.BOTH,
@@ -40,7 +40,7 @@ class LineSettingsConstructor(TestCase):
class LineSettingsAttributes(TestCase):
- def test_line_settings_attributes_are_mutable(self):
+ def test_line_settings_attributes_are_mutable(self) -> None:
settings = gpiod.LineSettings()
settings.direction = Direction.INPUT
@@ -60,12 +60,12 @@ class LineSettingsAttributes(TestCase):
class LineSettingsStringRepresentation(TestCase):
- def setUp(self):
+ def setUp(self) -> None:
self.settings = gpiod.LineSettings(
direction=Direction.OUTPUT, drive=Drive.OPEN_SOURCE, active_low=True
)
- def test_repr(self):
+ def test_repr(self) -> None:
self.assertEqual(
repr(self.settings),
"gpiod.LineSettings(direction=gpiod.line.Direction.OUTPUT, edge_detection=gpiod.line.Edge.NONE, bias=gpiod.line.Bias.AS_IS, drive=gpiod.line.Drive.OPEN_SOURCE, active_low=True, debounce_period=datetime.timedelta(0), event_clock=gpiod.line.Clock.MONOTONIC, output_value=gpiod.line.Value.INACTIVE)",
@@ -74,7 +74,7 @@ class LineSettingsStringRepresentation(TestCase):
cmp = eval(repr(self.settings))
self.assertEqual(self.settings, cmp)
- def test_str(self):
+ def test_str(self) -> None:
self.assertEqual(
str(self.settings),
"<LineSettings direction=Direction.OUTPUT edge_detection=Edge.NONE bias=Bias.AS_IS drive=Drive.OPEN_SOURCE active_low=True debounce_period=0:00:00 event_clock=Clock.MONOTONIC output_value=Value.INACTIVE>",
diff --git a/bindings/python/tests/tests_module.py b/bindings/python/tests/tests_module.py
index f46729feda86962d17907bc8b6b4e710fec3087e..2718624c7e0dd41259c7006e37d48f52cc279b1d 100644
--- a/bindings/python/tests/tests_module.py
+++ b/bindings/python/tests/tests_module.py
@@ -11,38 +11,38 @@ from .helpers import LinkGuard
class IsGPIOChip(TestCase):
- def test_is_gpiochip_bad(self):
+ def test_is_gpiochip_bad(self) -> None:
self.assertFalse(gpiod.is_gpiochip_device("/dev/null"))
self.assertFalse(gpiod.is_gpiochip_device("/dev/nonexistent"))
- def test_is_gpiochip_invalid_argument(self):
+ def test_is_gpiochip_invalid_argument(self) -> None:
with self.assertRaises(TypeError):
gpiod.is_gpiochip_device(4)
- def test_is_gpiochip_superfluous_argument(self):
+ def test_is_gpiochip_superfluous_argument(self) -> None:
with self.assertRaises(TypeError):
gpiod.is_gpiochip_device("/dev/null", 4)
- def test_is_gpiochip_missing_argument(self):
+ def test_is_gpiochip_missing_argument(self) -> None:
with self.assertRaises(TypeError):
gpiod.is_gpiochip_device()
- def test_is_gpiochip_good(self):
+ def test_is_gpiochip_good(self) -> None:
sim = gpiosim.Chip()
self.assertTrue(gpiod.is_gpiochip_device(sim.dev_path))
- def test_is_gpiochip_good_keyword_argument(self):
+ def test_is_gpiochip_good_keyword_argument(self) -> None:
sim = gpiosim.Chip()
self.assertTrue(gpiod.is_gpiochip_device(path=sim.dev_path))
- def test_is_gpiochip_link_good(self):
+ def test_is_gpiochip_link_good(self) -> None:
link = "/tmp/gpiod-py-test-link.{}".format(os.getpid())
sim = gpiosim.Chip()
with LinkGuard(sim.dev_path, link):
self.assertTrue(gpiod.is_gpiochip_device(link))
- def test_is_gpiochip_link_bad(self):
+ def test_is_gpiochip_link_bad(self) -> None:
link = "/tmp/gpiod-py-test-link.{}".format(os.getpid())
with LinkGuard("/dev/null", link):
@@ -52,8 +52,8 @@ class IsGPIOChip(TestCase):
class VersionString(TestCase):
VERSION_PATTERN = "^\\d+\\.\\d+(\\.\\d+|\\-devel|\\-rc\\d+)?$"
- def test_api_version_string(self):
+ def test_api_version_string(self) -> None:
self.assertRegex(gpiod.api_version, VersionString.VERSION_PATTERN)
- def test_module_version(self):
+ def test_module_version(self) -> None:
self.assertRegex(gpiod.__version__, VersionString.VERSION_PATTERN)
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 19/22] bindings: python: tests: ignore purposeful type errors
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
` (17 preceding siblings ...)
2024-09-27 18:53 ` [libgpiod][PATCH 18/22] bindings: python: tests: add missing type annotations Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 13:33 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 20/22] bindings: python: tests: annotate internal members Vincent Fazio
` (3 subsequent siblings)
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
bindings/python/tests/tests_chip.py | 12 ++++++------
bindings/python/tests/tests_chip_info.py | 6 +++---
bindings/python/tests/tests_info_event.py | 12 ++++++------
bindings/python/tests/tests_line_info.py | 2 +-
bindings/python/tests/tests_line_request.py | 16 ++++++++--------
bindings/python/tests/tests_module.py | 6 +++---
6 files changed, 27 insertions(+), 27 deletions(-)
diff --git a/bindings/python/tests/tests_chip.py b/bindings/python/tests/tests_chip.py
index 9c8f87579469e684ed3b6a5dbcef35e0856127ba..89d5df4341eceefbc0eed9b880ac641caa682af5 100644
--- a/bindings/python/tests/tests_chip.py
+++ b/bindings/python/tests/tests_chip.py
@@ -52,11 +52,11 @@ class ChipConstructor(TestCase):
def test_missing_path(self) -> None:
with self.assertRaises(TypeError):
- gpiod.Chip()
+ gpiod.Chip() # type: ignore[call-arg]
def test_invalid_type_for_path(self) -> None:
with self.assertRaises(TypeError):
- gpiod.Chip(4)
+ gpiod.Chip(4) # type: ignore[arg-type]
class ChipBooleanConversion(TestCase):
@@ -85,10 +85,10 @@ class ChipProperties(TestCase):
def test_properties_are_immutable(self) -> None:
with self.assertRaises(AttributeError):
- self.chip.path = "foobar"
+ self.chip.path = "foobar" # type: ignore[misc]
with self.assertRaises(AttributeError):
- self.chip.fd = 4
+ self.chip.fd = 4 # type: ignore[misc]
class ChipDevPathFromLink(TestCase):
@@ -172,7 +172,7 @@ class ClosedChipCannotBeUsed(TestCase):
chip.close()
with self.assertRaises(gpiod.ChipClosedError):
- chip.path
+ _ = chip.path
def test_close_chip_and_try_controlled_execution(self) -> None:
sim = gpiosim.Chip()
@@ -182,7 +182,7 @@ class ClosedChipCannotBeUsed(TestCase):
with self.assertRaises(gpiod.ChipClosedError):
with chip:
- chip.fd
+ _ = chip.fd
def test_close_chip_twice(self) -> None:
sim = gpiosim.Chip(label="foobar")
diff --git a/bindings/python/tests/tests_chip_info.py b/bindings/python/tests/tests_chip_info.py
index acb0da9d1f302186a2a6bca3e2f5a46abd3ebc51..99259af307fa25bc3ff39574a1bea1cc9dc254a6 100644
--- a/bindings/python/tests/tests_chip_info.py
+++ b/bindings/python/tests/tests_chip_info.py
@@ -31,13 +31,13 @@ class ChipInfoProperties(TestCase):
def test_chip_info_properties_are_immutable(self) -> None:
with self.assertRaises(AttributeError):
- self.info.name = "foobar"
+ self.info.name = "foobar" # type: ignore[misc]
with self.assertRaises(AttributeError):
- self.info.num_lines = 4
+ self.info.num_lines = 4 # type: ignore[misc]
with self.assertRaises(AttributeError):
- self.info.label = "foobar"
+ self.info.label = "foobar" # type: ignore[misc]
class ChipInfoStringRepresentation(TestCase):
diff --git a/bindings/python/tests/tests_info_event.py b/bindings/python/tests/tests_info_event.py
index 7e12b8e33f1a425423a1b2f30dd5af9a331906e9..1e6ab941799047c7e5383a6d0a2512c669655d19 100644
--- a/bindings/python/tests/tests_info_event.py
+++ b/bindings/python/tests/tests_info_event.py
@@ -28,13 +28,13 @@ class InfoEventDataclassBehavior(TestCase):
event = chip.read_info_event()
with self.assertRaises(FrozenInstanceError):
- event.event_type = 4
+ event.event_type = 4 # type: ignore[misc, assignment]
with self.assertRaises(FrozenInstanceError):
- event.timestamp_ns = 4
+ event.timestamp_ns = 4 # type: ignore[misc]
with self.assertRaises(FrozenInstanceError):
- event.line_info = 4
+ event.line_info = 4 # type: ignore[misc, assignment]
def request_reconfigure_release_line(chip_path: str, offset: int) -> None:
@@ -75,14 +75,14 @@ class WatchingInfoEventWorks(TestCase):
def test_watch_line_info_no_arguments(self) -> None:
with self.assertRaises(TypeError):
- self.chip.watch_line_info()
+ self.chip.watch_line_info() # type: ignore[call-arg]
def test_watch_line_info_by_line_name(self) -> None:
self.chip.watch_line_info("foobar")
def test_watch_line_info_invalid_argument_type(self) -> None:
with self.assertRaises(TypeError):
- self.chip.watch_line_info(None)
+ self.chip.watch_line_info(None) # type: ignore[arg-type]
def test_wait_for_event_timeout(self) -> None:
info = self.chip.watch_line_info(7)
@@ -161,7 +161,7 @@ class UnwatchingLineInfo(TestCase):
def test_unwatch_line_info_no_argument(self) -> None:
with self.assertRaises(TypeError):
- self.chip.unwatch_line_info()
+ self.chip.unwatch_line_info() # type: ignore[call-arg]
def test_unwatch_line_info_by_line_name(self) -> None:
self.chip.watch_line_info(4)
diff --git a/bindings/python/tests/tests_line_info.py b/bindings/python/tests/tests_line_info.py
index 9828349810eed0e3fa755f8557ec314d3e86ed7a..33d38a6de486447d326e8e3cb73934898ea2aba2 100644
--- a/bindings/python/tests/tests_line_info.py
+++ b/bindings/python/tests/tests_line_info.py
@@ -46,7 +46,7 @@ class GetLineInfo(TestCase):
def test_no_offset(self) -> None:
with self.assertRaises(TypeError):
- self.chip.get_line_info()
+ self.chip.get_line_info() # type: ignore[call-arg]
class LinePropertiesCanBeRead(TestCase):
diff --git a/bindings/python/tests/tests_line_request.py b/bindings/python/tests/tests_line_request.py
index 76edb1d273f103c1b2f72974f5364728f121b05b..bae8815b98654145c26071c4fc40816469313192 100644
--- a/bindings/python/tests/tests_line_request.py
+++ b/bindings/python/tests/tests_line_request.py
@@ -24,10 +24,10 @@ class ChipLineRequestsBehaveCorrectlyWithInvalidArguments(TestCase):
def test_passing_invalid_types_as_configs(self) -> None:
with self.assertRaises(AttributeError):
- self.chip.request_lines("foobar")
+ self.chip.request_lines("foobar") # type: ignore[arg-type]
with self.assertRaises(AttributeError):
- self.chip.request_lines(None, "foobar")
+ self.chip.request_lines(None, "foobar") # type: ignore[arg-type]
def test_offset_out_of_range(self) -> None:
with self.assertRaises(ValueError):
@@ -39,7 +39,7 @@ class ChipLineRequestsBehaveCorrectlyWithInvalidArguments(TestCase):
def test_request_no_arguments(self) -> None:
with self.assertRaises(TypeError):
- self.chip.request_lines()
+ self.chip.request_lines() # type: ignore[call-arg]
class ModuleLineRequestsBehaveCorrectlyWithInvalidArguments(TestCase):
@@ -51,10 +51,10 @@ class ModuleLineRequestsBehaveCorrectlyWithInvalidArguments(TestCase):
def test_passing_invalid_types_as_configs(self) -> None:
with self.assertRaises(AttributeError):
- gpiod.request_lines(self.sim.dev_path, "foobar")
+ gpiod.request_lines(self.sim.dev_path, "foobar") # type: ignore[arg-type]
with self.assertRaises(AttributeError):
- gpiod.request_lines(self.sim.dev_path, None, "foobar")
+ gpiod.request_lines(self.sim.dev_path, None, "foobar") # type: ignore[arg-type]
def test_offset_out_of_range(self) -> None:
with self.assertRaises(ValueError):
@@ -66,7 +66,7 @@ class ModuleLineRequestsBehaveCorrectlyWithInvalidArguments(TestCase):
def test_request_no_arguments(self) -> None:
with self.assertRaises(TypeError):
- gpiod.request_lines()
+ gpiod.request_lines() # type: ignore[call-arg]
class ChipLineRequestWorks(TestCase):
@@ -200,7 +200,7 @@ class LineRequestGettingValues(TestCase):
def test_get_values_invalid_argument_type(self) -> None:
with self.assertRaises(TypeError):
- self.req.get_values(True)
+ self.req.get_values(True) # type: ignore[arg-type]
class LineRequestGettingValuesByName(TestCase):
@@ -602,7 +602,7 @@ class ReleasedLineRequestCannotBeUsed(TestCase):
req.release()
with self.assertRaises(gpiod.RequestReleasedError):
- req.fd
+ _ = req.fd
class LineRequestSurvivesParentChip(TestCase):
diff --git a/bindings/python/tests/tests_module.py b/bindings/python/tests/tests_module.py
index 2718624c7e0dd41259c7006e37d48f52cc279b1d..efd49db59e6567b9bc5ee0096ccce3281ac466f3 100644
--- a/bindings/python/tests/tests_module.py
+++ b/bindings/python/tests/tests_module.py
@@ -17,15 +17,15 @@ class IsGPIOChip(TestCase):
def test_is_gpiochip_invalid_argument(self) -> None:
with self.assertRaises(TypeError):
- gpiod.is_gpiochip_device(4)
+ gpiod.is_gpiochip_device(4) # type: ignore[arg-type]
def test_is_gpiochip_superfluous_argument(self) -> None:
with self.assertRaises(TypeError):
- gpiod.is_gpiochip_device("/dev/null", 4)
+ gpiod.is_gpiochip_device("/dev/null", 4) # type: ignore[call-arg]
def test_is_gpiochip_missing_argument(self) -> None:
with self.assertRaises(TypeError):
- gpiod.is_gpiochip_device()
+ gpiod.is_gpiochip_device() # type: ignore[call-arg]
def test_is_gpiochip_good(self) -> None:
sim = gpiosim.Chip()
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 20/22] bindings: python: tests: annotate internal members
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
` (18 preceding siblings ...)
2024-09-27 18:53 ` [libgpiod][PATCH 19/22] bindings: python: tests: ignore purposeful type errors Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 13:34 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 21/22] bindings: python: tests: use f-strings Vincent Fazio
` (2 subsequent siblings)
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
bindings/python/tests/tests_chip.py | 10 +++++++---
bindings/python/tests/tests_chip_info.py | 13 ++++++++++---
bindings/python/tests/tests_edge_event.py | 11 +++++++++--
bindings/python/tests/tests_info_event.py | 30 +++++++++++++++++++++++++-----
bindings/python/tests/tests_line_info.py | 13 +++++++++++--
5 files changed, 62 insertions(+), 15 deletions(-)
diff --git a/bindings/python/tests/tests_chip.py b/bindings/python/tests/tests_chip.py
index 89d5df4341eceefbc0eed9b880ac641caa682af5..b719f6ba402c962b3ba8029cef61ed28fd1a525a 100644
--- a/bindings/python/tests/tests_chip.py
+++ b/bindings/python/tests/tests_chip.py
@@ -3,6 +3,7 @@
import errno
import os
+from typing import Optional
from unittest import TestCase
import gpiod
@@ -70,7 +71,7 @@ class ChipBooleanConversion(TestCase):
class ChipProperties(TestCase):
def setUp(self) -> None:
- self.sim = gpiosim.Chip()
+ self.sim: Optional[gpiosim.Chip] = gpiosim.Chip()
self.chip = gpiod.Chip(self.sim.dev_path)
def tearDown(self) -> None:
@@ -78,6 +79,7 @@ class ChipProperties(TestCase):
self.sim = None
def test_get_chip_path(self) -> None:
+ assert self.sim
self.assertEqual(self.sim.dev_path, self.chip.path)
def test_get_fd(self) -> None:
@@ -195,7 +197,7 @@ class ClosedChipCannotBeUsed(TestCase):
class StringRepresentation(TestCase):
def setUp(self) -> None:
- self.sim = gpiosim.Chip(num_lines=4, label="foobar")
+ self.sim: Optional[gpiosim.Chip] = gpiosim.Chip(num_lines=4, label="foobar")
self.chip = gpiod.Chip(self.sim.dev_path)
def tearDown(self) -> None:
@@ -203,12 +205,14 @@ class StringRepresentation(TestCase):
self.sim = None
def test_repr(self) -> None:
+ assert self.sim
self.assertEqual(repr(self.chip), 'gpiod.Chip("{}")'.format(self.sim.dev_path))
cmp = eval(repr(self.chip))
self.assertEqual(self.chip.path, cmp.path)
def test_str(self) -> None:
+ assert self.sim
info = self.chip.get_info()
self.assertEqual(
str(self.chip),
@@ -220,7 +224,7 @@ class StringRepresentation(TestCase):
class StringRepresentationClosed(TestCase):
def setUp(self) -> None:
- self.sim = gpiosim.Chip(num_lines=4, label="foobar")
+ self.sim: Optional[gpiosim.Chip] = gpiosim.Chip(num_lines=4, label="foobar")
self.chip = gpiod.Chip(self.sim.dev_path)
def tearDown(self) -> None:
diff --git a/bindings/python/tests/tests_chip_info.py b/bindings/python/tests/tests_chip_info.py
index 99259af307fa25bc3ff39574a1bea1cc9dc254a6..463f07ab8edeec7dde8dacc4829b86dd3b1d6ebd 100644
--- a/bindings/python/tests/tests_chip_info.py
+++ b/bindings/python/tests/tests_chip_info.py
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
+from typing import Optional
from unittest import TestCase
import gpiod
@@ -10,26 +11,32 @@ from . import gpiosim
class ChipInfoProperties(TestCase):
def setUp(self) -> None:
- self.sim = gpiosim.Chip(label="foobar", num_lines=16)
- self.chip = gpiod.Chip(self.sim.dev_path)
- self.info = self.chip.get_info()
+ self.sim: Optional[gpiosim.Chip] = gpiosim.Chip(label="foobar", num_lines=16)
+ self.chip: Optional[gpiod.Chip] = gpiod.Chip(self.sim.dev_path)
+ self.info: Optional[gpiod.ChipInfo] = self.chip.get_info()
def tearDown(self) -> None:
+ assert self.chip
self.info = None
self.chip.close()
self.chip = None
self.sim = None
def test_chip_info_name(self) -> None:
+ assert self.sim
+ assert self.info
self.assertEqual(self.info.name, self.sim.name)
def test_chip_info_label(self) -> None:
+ assert self.info
self.assertEqual(self.info.label, "foobar")
def test_chip_info_num_lines(self) -> None:
+ assert self.info
self.assertEqual(self.info.num_lines, 16)
def test_chip_info_properties_are_immutable(self) -> None:
+ assert self.info
with self.assertRaises(AttributeError):
self.info.name = "foobar" # type: ignore[misc]
diff --git a/bindings/python/tests/tests_edge_event.py b/bindings/python/tests/tests_edge_event.py
index f80d6a52680c48405b935fca8e47e2a2817a2fac..fc938f0492811631a1d3855f1c41203d3bc4a4fc 100644
--- a/bindings/python/tests/tests_edge_event.py
+++ b/bindings/python/tests/tests_edge_event.py
@@ -5,6 +5,7 @@ import time
from datetime import timedelta
from functools import partial
from threading import Thread
+from typing import Optional
from unittest import TestCase
import gpiod
@@ -53,8 +54,8 @@ class EdgeEventInvalidConfig(TestCase):
class WaitingForEdgeEvents(TestCase):
def setUp(self) -> None:
- self.sim = gpiosim.Chip(num_lines=8)
- self.thread = None
+ self.sim: Optional[gpiosim.Chip] = gpiosim.Chip(num_lines=8)
+ self.thread: Optional[Thread] = None
def tearDown(self) -> None:
if self.thread:
@@ -63,6 +64,7 @@ class WaitingForEdgeEvents(TestCase):
self.sim = None
def trigger_falling_and_rising_edge(self, offset: int) -> None:
+ assert self.sim
time.sleep(0.05)
self.sim.set_pull(offset, Pull.UP)
time.sleep(0.05)
@@ -71,12 +73,14 @@ class WaitingForEdgeEvents(TestCase):
def trigger_rising_edge_events_on_two_offsets(
self, offset0: int, offset1: int
) -> None:
+ assert self.sim
time.sleep(0.05)
self.sim.set_pull(offset0, Pull.UP)
time.sleep(0.05)
self.sim.set_pull(offset1, Pull.UP)
def test_both_edge_events(self) -> None:
+ assert self.sim
with gpiod.request_lines(
self.sim.dev_path, {2: gpiod.LineSettings(edge_detection=Edge.BOTH)}
) as req:
@@ -104,6 +108,7 @@ class WaitingForEdgeEvents(TestCase):
self.assertGreater(ts_falling, ts_rising)
def test_rising_edge_event(self) -> None:
+ assert self.sim
with gpiod.request_lines(
self.sim.dev_path, {6: gpiod.LineSettings(edge_detection=Edge.RISING)}
) as req:
@@ -122,6 +127,7 @@ class WaitingForEdgeEvents(TestCase):
self.assertFalse(req.wait_edge_events(timedelta(microseconds=10000)))
def test_falling_edge_event(self) -> None:
+ assert self.sim
with gpiod.request_lines(
self.sim.dev_path, {6: gpiod.LineSettings(edge_detection=Edge.FALLING)}
) as req:
@@ -140,6 +146,7 @@ class WaitingForEdgeEvents(TestCase):
self.assertFalse(req.wait_edge_events(timedelta(microseconds=10000)))
def test_sequence_numbers(self) -> None:
+ assert self.sim
with gpiod.request_lines(
self.sim.dev_path, {(2, 4): gpiod.LineSettings(edge_detection=Edge.BOTH)}
) as req:
diff --git a/bindings/python/tests/tests_info_event.py b/bindings/python/tests/tests_info_event.py
index 1e6ab941799047c7e5383a6d0a2512c669655d19..3328335d478ff694e8b2ff3189738475af0a783e 100644
--- a/bindings/python/tests/tests_info_event.py
+++ b/bindings/python/tests/tests_info_event.py
@@ -7,6 +7,7 @@ import threading
import time
from dataclasses import FrozenInstanceError
from functools import partial
+from typing import Optional
from unittest import TestCase
import gpiod
@@ -49,48 +50,60 @@ def request_reconfigure_release_line(chip_path: str, offset: int) -> None:
class WatchingInfoEventWorks(TestCase):
def setUp(self) -> None:
- self.sim = gpiosim.Chip(num_lines=8, line_names={4: "foobar"})
- self.chip = gpiod.Chip(self.sim.dev_path)
- self.thread = None
+ self.sim: Optional[gpiosim.Chip] = gpiosim.Chip(
+ num_lines=8, line_names={4: "foobar"}
+ )
+ self.chip: Optional[gpiod.Chip] = gpiod.Chip(self.sim.dev_path)
+ self.thread: Optional[threading.Thread] = None
def tearDown(self) -> None:
if self.thread:
self.thread.join()
self.thread = None
+ assert self.chip
self.chip.close()
self.chip = None
self.sim = None
def test_watch_line_info_returns_line_info(self) -> None:
+ assert self.chip
info = self.chip.watch_line_info(7)
self.assertEqual(info.offset, 7)
def test_watch_line_info_keyword_argument(self) -> None:
+ assert self.chip
info = self.chip.watch_line_info(line=7)
def test_watch_line_info_offset_out_of_range(self) -> None:
+ assert self.chip
with self.assertRaises(ValueError):
self.chip.watch_line_info(8)
def test_watch_line_info_no_arguments(self) -> None:
+ assert self.chip
with self.assertRaises(TypeError):
self.chip.watch_line_info() # type: ignore[call-arg]
def test_watch_line_info_by_line_name(self) -> None:
+ assert self.chip
self.chip.watch_line_info("foobar")
def test_watch_line_info_invalid_argument_type(self) -> None:
+ assert self.chip
with self.assertRaises(TypeError):
self.chip.watch_line_info(None) # type: ignore[arg-type]
def test_wait_for_event_timeout(self) -> None:
+ assert self.chip
info = self.chip.watch_line_info(7)
self.assertFalse(
self.chip.wait_info_event(datetime.timedelta(microseconds=10000))
)
def test_request_reconfigure_release_events(self) -> None:
+ assert self.chip
+ assert self.sim
info = self.chip.watch_line_info(7)
self.assertEqual(info.direction, Direction.INPUT)
@@ -133,15 +146,19 @@ class WatchingInfoEventWorks(TestCase):
class UnwatchingLineInfo(TestCase):
def setUp(self) -> None:
- self.sim = gpiosim.Chip(num_lines=8, line_names={4: "foobar"})
- self.chip = gpiod.Chip(self.sim.dev_path)
+ self.sim: Optional[gpiosim.Chip] = gpiosim.Chip(
+ num_lines=8, line_names={4: "foobar"}
+ )
+ self.chip: Optional[gpiod.Chip] = gpiod.Chip(self.sim.dev_path)
def tearDown(self) -> None:
+ assert self.chip
self.chip.close()
self.chip = None
self.sim = None
def test_unwatch_line_info(self) -> None:
+ assert self.chip
self.chip.watch_line_info(0)
with self.chip.request_lines(config={0: None}) as request:
self.assertTrue(self.chip.wait_info_event(datetime.timedelta(seconds=1)))
@@ -154,16 +171,19 @@ class UnwatchingLineInfo(TestCase):
)
def test_unwatch_not_watched_line(self) -> None:
+ assert self.chip
with self.assertRaises(OSError) as ex:
self.chip.unwatch_line_info(2)
self.assertEqual(ex.exception.errno, errno.EBUSY)
def test_unwatch_line_info_no_argument(self) -> None:
+ assert self.chip
with self.assertRaises(TypeError):
self.chip.unwatch_line_info() # type: ignore[call-arg]
def test_unwatch_line_info_by_line_name(self) -> None:
+ assert self.chip
self.chip.watch_line_info(4)
with self.chip.request_lines(config={4: None}) as request:
self.assertIsNotNone(self.chip.read_info_event())
diff --git a/bindings/python/tests/tests_line_info.py b/bindings/python/tests/tests_line_info.py
index 33d38a6de486447d326e8e3cb73934898ea2aba2..7215221ac1fb3b2a0730c189321cdea498da8226 100644
--- a/bindings/python/tests/tests_line_info.py
+++ b/bindings/python/tests/tests_line_info.py
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
+from typing import Optional
from unittest import TestCase
import gpiod
@@ -13,38 +14,46 @@ HogDir = gpiosim.Chip.Direction
class GetLineInfo(TestCase):
def setUp(self) -> None:
- self.sim = gpiosim.Chip(
+ self.sim: Optional[gpiosim.Chip] = gpiosim.Chip(
num_lines=4,
line_names={0: "foobar"},
)
- self.chip = gpiod.Chip(self.sim.dev_path)
+ self.chip: Optional[gpiod.Chip] = gpiod.Chip(self.sim.dev_path)
def tearDown(self) -> None:
+ assert self.chip
self.chip.close()
self.chip = None
self.sim = None
def test_get_line_info_by_offset(self) -> None:
+ assert self.chip
self.chip.get_line_info(0)
def test_get_line_info_by_offset_keyword(self) -> None:
+ assert self.chip
self.chip.get_line_info(line=0)
def test_get_line_info_by_name(self) -> None:
+ assert self.chip
self.chip.get_line_info("foobar")
def test_get_line_info_by_name_keyword(self) -> None:
+ assert self.chip
self.chip.get_line_info(line="foobar")
def test_get_line_info_by_offset_string(self) -> None:
+ assert self.chip
self.chip.get_line_info("2")
def test_offset_out_of_range(self) -> None:
+ assert self.chip
with self.assertRaises(ValueError) as ex:
self.chip.get_line_info(4)
def test_no_offset(self) -> None:
+ assert self.chip
with self.assertRaises(TypeError):
self.chip.get_line_info() # type: ignore[call-arg]
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 21/22] bindings: python: tests: use f-strings
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
` (19 preceding siblings ...)
2024-09-27 18:53 ` [libgpiod][PATCH 20/22] bindings: python: tests: annotate internal members Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 13:35 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 22/22] bindings: python: configure and document dev dependencies Vincent Fazio
2024-10-08 13:37 ` [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Bartosz Golaszewski
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
bindings/python/tests/__init__.py | 4 +---
bindings/python/tests/tests_chip.py | 10 ++++------
bindings/python/tests/tests_chip_info.py | 2 +-
bindings/python/tests/tests_line_request.py | 4 +---
bindings/python/tests/tests_module.py | 4 ++--
5 files changed, 9 insertions(+), 15 deletions(-)
diff --git a/bindings/python/tests/__init__.py b/bindings/python/tests/__init__.py
index 2374e8155373efbd94d5c66dcfdffa7cc23be9f6..a0f22ae717271766b4175a775cc6ec19c9b24441 100644
--- a/bindings/python/tests/__init__.py
+++ b/bindings/python/tests/__init__.py
@@ -9,7 +9,5 @@ current_version = LooseVersion(os.uname().release.split("-")[0])
if current_version < required_kernel_version:
raise NotImplementedError(
- "linux kernel version must be at least {} - got {}".format(
- required_kernel_version, current_version
- )
+ f"linux kernel version must be at least {required_kernel_version} - got {current_version}"
)
diff --git a/bindings/python/tests/tests_chip.py b/bindings/python/tests/tests_chip.py
index b719f6ba402c962b3ba8029cef61ed28fd1a525a..3ea2be1d272d0ba5fca59c51f08962508505efb9 100644
--- a/bindings/python/tests/tests_chip.py
+++ b/bindings/python/tests/tests_chip.py
@@ -26,7 +26,7 @@ class ChipConstructor(TestCase):
pass
def test_open_chip_by_link(self) -> None:
- link = "/tmp/gpiod-py-test-link.{}".format(os.getpid())
+ link = f"/tmp/gpiod-py-test-link.{os.getpid()}"
sim = gpiosim.Chip()
with LinkGuard(sim.dev_path, link):
@@ -96,7 +96,7 @@ class ChipProperties(TestCase):
class ChipDevPathFromLink(TestCase):
def test_dev_path_open_by_link(self) -> None:
sim = gpiosim.Chip()
- link = "/tmp/gpiod-py-test-link.{}".format(os.getpid())
+ link = f"/tmp/gpiod-py-test-link.{os.getpid()}"
with LinkGuard(sim.dev_path, link):
with gpiod.Chip(link) as chip:
@@ -206,7 +206,7 @@ class StringRepresentation(TestCase):
def test_repr(self) -> None:
assert self.sim
- self.assertEqual(repr(self.chip), 'gpiod.Chip("{}")'.format(self.sim.dev_path))
+ self.assertEqual(repr(self.chip), f'gpiod.Chip("{self.sim.dev_path}")')
cmp = eval(repr(self.chip))
self.assertEqual(self.chip.path, cmp.path)
@@ -216,9 +216,7 @@ class StringRepresentation(TestCase):
info = self.chip.get_info()
self.assertEqual(
str(self.chip),
- '<Chip path="{}" fd={} info=<ChipInfo name="{}" label="foobar" num_lines=4>>'.format(
- self.sim.dev_path, self.chip.fd, info.name
- ),
+ f'<Chip path="{self.sim.dev_path}" fd={self.chip.fd} info=<ChipInfo name="{info.name}" label="foobar" num_lines=4>>',
)
diff --git a/bindings/python/tests/tests_chip_info.py b/bindings/python/tests/tests_chip_info.py
index 463f07ab8edeec7dde8dacc4829b86dd3b1d6ebd..8d0a2f955edeb7fe8a285e9951f6b4d392f4490d 100644
--- a/bindings/python/tests/tests_chip_info.py
+++ b/bindings/python/tests/tests_chip_info.py
@@ -56,5 +56,5 @@ class ChipInfoStringRepresentation(TestCase):
self.assertEqual(
str(info),
- '<ChipInfo name="{}" label="foobar" num_lines=16>'.format(sim.name),
+ f'<ChipInfo name="{sim.name}" label="foobar" num_lines=16>',
)
diff --git a/bindings/python/tests/tests_line_request.py b/bindings/python/tests/tests_line_request.py
index bae8815b98654145c26071c4fc40816469313192..afee644558b5e734b50a6d90dd6a0a867f466eb7 100644
--- a/bindings/python/tests/tests_line_request.py
+++ b/bindings/python/tests/tests_line_request.py
@@ -635,9 +635,7 @@ class LineRequestStringRepresentation(TestCase):
with chip.request_lines(config={(2, 6, 4, 1): None}) as req:
self.assertEqual(
str(req),
- '<LineRequest chip="{}" num_lines=4 offsets=[2, 6, 4, 1] fd={}>'.format(
- self.sim.name, req.fd
- ),
+ f'<LineRequest chip="{self.sim.name}" num_lines=4 offsets=[2, 6, 4, 1] fd={req.fd}>',
)
def test_str_released(self) -> None:
diff --git a/bindings/python/tests/tests_module.py b/bindings/python/tests/tests_module.py
index efd49db59e6567b9bc5ee0096ccce3281ac466f3..7120c6346ba4666adb250d0880d5777dbb7666ea 100644
--- a/bindings/python/tests/tests_module.py
+++ b/bindings/python/tests/tests_module.py
@@ -36,14 +36,14 @@ class IsGPIOChip(TestCase):
self.assertTrue(gpiod.is_gpiochip_device(path=sim.dev_path))
def test_is_gpiochip_link_good(self) -> None:
- link = "/tmp/gpiod-py-test-link.{}".format(os.getpid())
+ link = f"/tmp/gpiod-py-test-link.{os.getpid()}"
sim = gpiosim.Chip()
with LinkGuard(sim.dev_path, link):
self.assertTrue(gpiod.is_gpiochip_device(link))
def test_is_gpiochip_link_bad(self) -> None:
- link = "/tmp/gpiod-py-test-link.{}".format(os.getpid())
+ link = f"/tmp/gpiod-py-test-link.{os.getpid()}"
with LinkGuard("/dev/null", link):
self.assertFalse(gpiod.is_gpiochip_device(link))
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [libgpiod][PATCH 22/22] bindings: python: configure and document dev dependencies
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
` (20 preceding siblings ...)
2024-09-27 18:53 ` [libgpiod][PATCH 21/22] bindings: python: tests: use f-strings Vincent Fazio
@ 2024-09-27 18:53 ` Vincent Fazio
2024-10-08 13:35 ` Bartosz Golaszewski
2024-10-08 13:37 ` [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Bartosz Golaszewski
22 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-09-27 18:53 UTC (permalink / raw)
To: linux-gpio; +Cc: vfazio, Vincent Fazio
Mypy [0] is a popular static type checker that validates attribute and
variable use and ensures function arguments adhere to type annotations.
Ruff [1] is a popular Rust-based Python linter and code formatter. It
has support for a large set of linting rules [2] and largely complies
with the Black format [3].
Add documentation to the README for how to run the tools.
[0]: https://mypy.readthedocs.io/en/stable/
[1]: https://docs.astral.sh/ruff/
[2]: https://docs.astral.sh/ruff/rules/
[3]: https://docs.astral.sh/ruff/formatter/#black-compatibility
Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
---
bindings/python/README.md | 17 +++++++++++++++++
bindings/python/pyproject.toml | 36 ++++++++++++++++++++++++++++++++++++
2 files changed, 53 insertions(+)
diff --git a/bindings/python/README.md b/bindings/python/README.md
index cb5cee62cc46980ce2484bc85d8686ffb8622e59..89c824cebbd735624159a5b30a8bbee2c55e896e 100644
--- a/bindings/python/README.md
+++ b/bindings/python/README.md
@@ -112,3 +112,20 @@ make python-tests-run
from the `libgpiod/bindings/python` directory as root (necessary to be able
to create the **gpio-sims** used for testing).
+
+## Linting/Formatting
+
+When making changes, ensure type checks and linting still pass:
+
+```
+python3 -m venv venv
+. venv/bin/activate
+pip install mypy ruff
+mypy; ruff format; ruff check
+```
+
+Ideally the gpiod library will continue to pass strict checks:
+
+```
+mypy --strict
+```
\ No newline at end of file
diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml
index f6bf43c0a20edc76bfa51a98e7d523c8dadefea1..43e85a72daaea50c07a527d7b388ac9a4396a3d8 100644
--- a/bindings/python/pyproject.toml
+++ b/bindings/python/pyproject.toml
@@ -3,3 +3,39 @@
[build-system]
requires = ["setuptools", "wheel", "packaging"]
+
+[tool.mypy]
+python_version = "3.9"
+files = [
+ "gpiod/",
+ "tests/",
+]
+
+[[tool.mypy.overrides]]
+module = "gpiod.line.*"
+strict_equality = false # Ignore Enum comparison-overlap https://github.com/python/mypy/issues/17317
+
+[tool.ruff]
+target-version = "py39"
+include = [
+ "gpiod/**/*.py",
+ "gpiod/**/*.pyi",
+ "tests/**/*.py",
+ "tests/**/*.pyi",
+]
+
+[tool.ruff.lint]
+select = ["B", "E", "F", "I", "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",
+ # Ignore new Union (|) syntax until we require 3.10+
+ "UP007",
+]
+
+[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
\ No newline at end of file
--
2.34.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 01/22] bindings: python: clean up imports and exports
2024-09-27 18:53 ` [libgpiod][PATCH 01/22] bindings: python: clean up imports and exports Vincent Fazio
@ 2024-10-08 11:16 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 11:16 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 9:05 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
> Remove unused imports and sort the remainder following isort rules.
>
> Update submodules to use lists for `__all__` for ease of re-exporting
> public classes from within gpiod.
>
> Also, fix instances where `line` wasn't imported via a relative import.
> The library now consistently uses relative imports for submodules.
>
> Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
> ---
This definitely improves the output of help(gpiod) but I was under the
impression that we discussed re-exporting the definitions from
gpiod.line directly from gpiod and I argued that this isn't really a
good idea as they do fall under the umbrella of "line" definitions and
should be imported from gpiod.line explicitly. I thought it would work
more like:
>>> from gpiod import *
# now we also imported line
>>> line.Direction.OUTPUT
<Direction.OUTPUT: 3>
Is there any reason for not doing it this way?
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 02/22] bindings: python: make internal a private submodule
2024-09-27 18:53 ` [libgpiod][PATCH 02/22] bindings: python: make internal a private submodule Vincent Fazio
@ 2024-10-08 11:24 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 11:24 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 9:05 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
> The internal submodule shouldn't be exposed as part of the public
> interface, so mark it private following PEP 8 convention [0].
>
> Also, add a type annotation to `sec` for its possible types.
>
> [0]: https://peps.python.org/pep-0008/#public-and-internal-interfaces
> Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
> ---
> bindings/python/gpiod/{internal.py => _internal.py} | 1 +
> bindings/python/gpiod/chip.py | 2 +-
> bindings/python/gpiod/line_request.py | 2 +-
> 3 files changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/bindings/python/gpiod/internal.py b/bindings/python/gpiod/_internal.py
> similarity index 94%
> rename from bindings/python/gpiod/internal.py
> rename to bindings/python/gpiod/_internal.py
> index d1e95e4ade3146f596643d52207b367e332e6f7e..c9b5d2850389d5314a12bf6d151774a96469a085 100644
> --- a/bindings/python/gpiod/internal.py
> +++ b/bindings/python/gpiod/_internal.py
> @@ -9,6 +9,7 @@ __all__ = ["poll_fd"]
>
>
> def poll_fd(fd: int, timeout: Optional[Union[timedelta, float]] = None) -> bool:
> + sec: Union[float, None]
This has nothing to do with marking internal as private. Can this be a
separate commit?
Otherwise, looks good.
Bart
> if isinstance(timeout, timedelta):
> sec = timeout.total_seconds()
> else:
> diff --git a/bindings/python/gpiod/chip.py b/bindings/python/gpiod/chip.py
> index 257a31eba8d19634fd14e3b1d33a1345a0363946..1a1bba4d6dd9e840a60394f1b74903f6ad15a0f4 100644
> --- a/bindings/python/gpiod/chip.py
> +++ b/bindings/python/gpiod/chip.py
> @@ -7,10 +7,10 @@ from errno import ENOENT
> from typing import Optional, Union
>
> from . import _ext
> +from ._internal import poll_fd
> from .chip_info import ChipInfo
> from .exception import ChipClosedError
> from .info_event import InfoEvent
> -from .internal import poll_fd
> from .line import Value
> from .line_info import LineInfo
> from .line_request import LineRequest
> diff --git a/bindings/python/gpiod/line_request.py b/bindings/python/gpiod/line_request.py
> index e48830450dcb5b7fa6c7983a0fe074cd9bd32ab7..154174872e488fa478b27f5e83d65e6040aca367 100644
> --- a/bindings/python/gpiod/line_request.py
> +++ b/bindings/python/gpiod/line_request.py
> @@ -6,9 +6,9 @@ from datetime import timedelta
> from typing import Optional, Union
>
> from . import _ext
> +from ._internal import poll_fd
> from .edge_event import EdgeEvent
> from .exception import RequestReleasedError
> -from .internal import poll_fd
> from .line import Value
> from .line_settings import LineSettings, _line_settings_to_ext
>
>
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 03/22] bindings: python: fix annotation of variable length tuples
2024-09-27 18:53 ` [libgpiod][PATCH 03/22] bindings: python: fix annotation of variable length tuples Vincent Fazio
@ 2024-10-08 13:02 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 13:02 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 9:05 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
> Both `Chip.request_lines` and `LineRequest.reconfigure_lines` accept a
> config argument that is allowed to be either a variable length tuple
> of int | str, a str, or an int.
>
> Python documentation [0] points out that variable length tuples need a
> trailing ellipsis in their annotation.
>
> [0]: https://docs.python.org/3/library/typing.html#annotating-tuples
> Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
> ---
For my own reference: looks good.
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 04/22] bindings: python: add missing method type annotations
2024-09-27 18:53 ` [libgpiod][PATCH 04/22] bindings: python: add missing method type annotations Vincent Fazio
@ 2024-10-08 13:07 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 13:07 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 9:05 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
> Explicitly define the arguments for `gpiod.request_lines` so there is a
> clearer linkage with the underlying `Chip.request_lines` interface.
>
> Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
> ---
> bindings/python/gpiod/__init__.py | 17 +++++++++++++++--
> bindings/python/gpiod/chip.py | 12 ++++++++++--
> bindings/python/gpiod/chip_info.py | 2 +-
> bindings/python/gpiod/edge_event.py | 2 +-
> bindings/python/gpiod/exception.py | 4 ++--
> bindings/python/gpiod/info_event.py | 2 +-
> bindings/python/gpiod/line.py | 2 +-
> bindings/python/gpiod/line_info.py | 2 +-
> bindings/python/gpiod/line_request.py | 16 ++++++++++++----
> bindings/python/gpiod/line_settings.py | 4 ++--
> 10 files changed, 46 insertions(+), 17 deletions(-)
>
> diff --git a/bindings/python/gpiod/__init__.py b/bindings/python/gpiod/__init__.py
> index 4d916f7f1a4eabd8ad1b2844262c20ed01a0798c..3cf39d61f64c3888584cd2518787b8e17e185ed2 100644
> --- a/bindings/python/gpiod/__init__.py
> +++ b/bindings/python/gpiod/__init__.py
> @@ -7,6 +7,8 @@ Python bindings for libgpiod.
> This module wraps the native C API of libgpiod in a set of python classes.
> """
>
> +from typing import Optional, Union
> +
> from . import (
> _ext,
> chip,
> @@ -83,7 +85,13 @@ def is_gpiochip_device(path: str) -> bool:
> return _ext.is_gpiochip_device(path)
>
>
> -def request_lines(path: str, *args, **kwargs) -> LineRequest:
> +def request_lines(
> + path: str,
> + config: dict[Union[tuple[Union[int, str], ...], int, str], Optional[LineSettings]],
> + consumer: Optional[str] = None,
> + event_buffer_size: Optional[int] = None,
> + output_values: Optional[dict[Union[int, str], line.Value]] = None,
> +) -> LineRequest:
> """
> Open a GPIO chip pointed to by 'path', request lines according to the
> configuration arguments, close the chip and return the request object.
> @@ -99,4 +107,9 @@ def request_lines(path: str, *args, **kwargs) -> LineRequest:
> Returns a new LineRequest object.
> """
> with Chip(path) as chip:
> - return chip.request_lines(*args, **kwargs)
> + return chip.request_lines(
> + config=config,
> + consumer=consumer,
> + event_buffer_size=event_buffer_size,
> + output_values=output_values,
> + )
IMO this and the rest of this patch should become separate commits.
Otherwise looks good.
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 05/22] bindings: python: add type stubs for _ext
2024-09-27 18:53 ` [libgpiod][PATCH 05/22] bindings: python: add type stubs for _ext Vincent Fazio
@ 2024-10-08 13:08 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 13:08 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 8:57 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
No empty commit messages please.
> Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
> ---
> bindings/python/gpiod/_ext.pyi | 93 ++++++++++++++++++++++++++++++++++++++++++
> bindings/python/setup.py | 2 +-
> 2 files changed, 94 insertions(+), 1 deletion(-)
>
> diff --git a/bindings/python/gpiod/_ext.pyi b/bindings/python/gpiod/_ext.pyi
> new file mode 100644
> index 0000000000000000000000000000000000000000..1beb80dde9f080b729374b9dc69322c01fc37889
> --- /dev/null
> +++ b/bindings/python/gpiod/_ext.pyi
> @@ -0,0 +1,93 @@
> +# SPDX-License-Identifier: LGPL-2.1-or-later
> +# SPDX-FileCopyrightText: 2024 Vincent Fazio <vfazio@gmail.com>
> +
> +from typing import Optional
> +
> +from .chip_info import ChipInfo
> +from .edge_event import EdgeEvent
> +from .info_event import InfoEvent
> +from .line import Value
> +from .line_info import LineInfo
> +
> +class LineSettings:
> + def __init__(
> + self,
> + direction: int,
> + edge_detection: int,
> + bias: int,
> + drive: int,
> + active_low: bool,
> + debounce_period: int,
> + event_clock: int,
> + output_value: int,
> + ) -> None: ...
> +
> +class LineConfig:
> + def __init__(self) -> None: ...
> + def add_line_settings(self, offsets: list[int], settings: LineSettings) -> None: ...
> + def set_output_values(self, global_output_values: list[Value]) -> None: ...
> +
> +class Request:
> + def release(self) -> None: ...
> + def get_values(self, offsets: list[int], values: list[Value]) -> None: ...
> + def set_values(self, values: dict[int, Value]) -> None: ...
> + def reconfigure_lines(self, line_cfg: LineConfig) -> None: ...
> + def read_edge_events(self, max_events: Optional[int]) -> list[EdgeEvent]: ...
> + @property
> + def chip_name(self) -> str: ...
> + @property
> + def num_lines(self) -> int: ...
> + @property
> + def offsets(self) -> list[int]: ...
> + @property
> + def fd(self) -> int: ...
> +
> +class Chip:
> + def __init__(self, path: str) -> None: ...
> + def get_info(self) -> ChipInfo: ...
> + def line_offset_from_id(self, id: str) -> int: ...
> + def get_line_info(self, offset: int, watch: bool) -> LineInfo: ...
> + def request_lines(
> + self,
> + line_cfg: LineConfig,
> + consumer: Optional[str],
> + event_buffer_size: Optional[int],
> + ) -> Request: ...
> + def read_info_event(self) -> InfoEvent: ...
> + def close(self) -> None: ...
> + def unwatch_line_info(self, line: int) -> None: ...
> + @property
> + def path(self) -> str: ...
> + @property
> + def fd(self) -> int: ...
> +
> +def is_gpiochip_device(path: str) -> bool: ...
> +
> +api_version: str
> +
> +# enum constants
> +BIAS_AS_IS: int
> +BIAS_DISABLED: int
> +BIAS_PULL_DOWN: int
> +BIAS_PULL_UP: int
> +BIAS_UNKNOWN: int
> +CLOCK_HTE: int
> +CLOCK_MONOTONIC: int
> +CLOCK_REALTIME: int
> +DIRECTION_AS_IS: int
> +DIRECTION_INPUT: int
> +DIRECTION_OUTPUT: int
> +DRIVE_OPEN_DRAIN: int
> +DRIVE_OPEN_SOURCE: int
> +DRIVE_PUSH_PULL: int
> +EDGE_BOTH: int
> +EDGE_EVENT_TYPE_FALLING: int
> +EDGE_EVENT_TYPE_RISING: int
> +EDGE_FALLING: int
> +EDGE_NONE: int
> +EDGE_RISING: int
> +INFO_EVENT_TYPE_LINE_CONFIG_CHANGED: int
> +INFO_EVENT_TYPE_LINE_RELEASED: int
> +INFO_EVENT_TYPE_LINE_REQUESTED: int
> +VALUE_ACTIVE: int
> +VALUE_INACTIVE: int
> diff --git a/bindings/python/setup.py b/bindings/python/setup.py
> index 1f04b9939b47dc7b960679b6f24e87a6f2a4e46f..54790dfd88e77762719fce3d9194499e8ff39d73 100644
> --- a/bindings/python/setup.py
> +++ b/bindings/python/setup.py
> @@ -224,7 +224,7 @@ setup(
> name="gpiod",
> url="https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git",
> packages=find_packages(exclude=["tests", "tests.*"]),
> - package_data={"gpiod": ["py.typed"]},
> + package_data={"gpiod": ["py.typed", "_ext.pyi"]},
> python_requires=">=3.9.0",
> ext_modules=[gpiod_ext],
> cmdclass={"build_ext": build_ext, "sdist": sdist},
>
> --
> 2.34.1
>
I had no idea this was possible, thanks!
Looks good.
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 06/22] bindings: python: annotate internal members of Chip
2024-09-27 18:53 ` [libgpiod][PATCH 06/22] bindings: python: annotate internal members of Chip Vincent Fazio
@ 2024-10-08 13:09 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 13:09 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 8:57 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
> Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
> ---
> bindings/python/gpiod/chip.py | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/bindings/python/gpiod/chip.py b/bindings/python/gpiod/chip.py
> index 75cc337e74bc965a30962b39a1584b13b4c4b067..4aa5677f94caf8c5d863aa6d75915a5b650de137 100644
> --- a/bindings/python/gpiod/chip.py
> +++ b/bindings/python/gpiod/chip.py
> @@ -57,8 +57,8 @@ class Chip:
> path:
> Path to the GPIO character device file.
> """
> - self._chip = _ext.Chip(path)
> - self._info = None
> + self._chip: Union[_ext.Chip, None] = _ext.Chip(path)
> + self._info: Union[ChipInfo, None] = None
>
> def __bool__(self) -> bool:
> """
>
> --
> 2.34.1
>
Needs, commit message. Otherwise looks good.
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 07/22] bindings: python: fix Chip union-attr type errors
2024-09-27 18:53 ` [libgpiod][PATCH 07/22] bindings: python: fix Chip union-attr type errors Vincent Fazio
@ 2024-10-08 13:16 ` Bartosz Golaszewski
2024-10-08 14:57 ` Vincent Fazio
0 siblings, 1 reply; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 13:16 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 8:57 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
> Since `Chip._chip` can be `None`, it's necessary to inform type checkers
> of the state of the object to silence the union-attr errors.
>
> Type checkers may not be able to infer that an object is not `None` from
> an earlier call (such as `_check_closed`).
>
> 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.
>
> Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
> ---
> bindings/python/gpiod/chip.py | 11 ++++++++++-
> 1 file changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/bindings/python/gpiod/chip.py b/bindings/python/gpiod/chip.py
> index 4aa5677f94caf8c5d863aa6d75915a5b650de137..fe7bcfe082d6e9f6220093d3fc45ff232b5d0d17 100644
> --- a/bindings/python/gpiod/chip.py
> +++ b/bindings/python/gpiod/chip.py
> @@ -7,7 +7,7 @@ from collections import Counter
> from datetime import timedelta
> from errno import ENOENT
> from types import TracebackType
> -from typing import Optional, Union
> +from typing import Optional, Union, cast
>
> from . import _ext
> from ._internal import poll_fd
> @@ -97,6 +97,7 @@ class Chip:
> longer be used after this method is called.
> """
> self._check_closed()
> + self._chip = cast(_ext.Chip, self._chip)
> self._chip.close()
> self._chip = None
>
Ok, so I don't really understand what is happening here. We're going
to re-assign _chip in every function? What happens to cast() if _chip
IS None?
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 08/22] bindings: python: annotate internal members of LineRequest
2024-09-27 18:53 ` [libgpiod][PATCH 08/22] bindings: python: annotate internal members of LineRequest Vincent Fazio
@ 2024-10-08 13:17 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 13:17 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 8:57 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
> Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
> ---
> bindings/python/gpiod/line_request.py | 7 ++++++-
> 1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/bindings/python/gpiod/line_request.py b/bindings/python/gpiod/line_request.py
> index f94b6b50d72486da1446abcda8282a8dc6d6e620..77d199ac64e9d3cc68d4a8b38dd0f571a24ab231 100644
> --- a/bindings/python/gpiod/line_request.py
> +++ b/bindings/python/gpiod/line_request.py
> @@ -30,7 +30,12 @@ class LineRequest:
> LineRequest objects can only be instantiated by a Chip parent. This is
> not part of stable API.
> """
> - self._req = req
> + self._req: Union[_ext.Request, None] = req
> + self._chip_name: str
> + self._offsets: list[int]
> + self._name_map: dict[str, int]
> + self._offset_map: dict[int, str]
> + self._lines: list[Union[int, str]]
>
> def __bool__(self) -> bool:
> """
>
> --
> 2.34.1
>
+commit message and LGTM
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 09/22] bindings: python: fix LineRequest union-attr type errors
2024-09-27 18:53 ` [libgpiod][PATCH 09/22] bindings: python: fix LineRequest union-attr type errors Vincent Fazio
@ 2024-10-08 13:18 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 13:18 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 8:57 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
> Since `LineRequest._req` can be `None`, it's necessary to inform type
> checkers of the state of the object to silence the union-attr errors.
>
> Type checkers may not be able to infer that an object is not `None` from
> an earlier call (such as `_check_released`).
>
> 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.
>
> Also, convert singular ints or strs to a tuple instead of a list to keep
> with the inferred variable type of `lines`.
>
> Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
> ---
Basically the same questions as with Chip. Is this a common pattern in the wild?
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 10/22] bindings: python: convert lines to offsets in LineRequest
2024-09-27 18:53 ` [libgpiod][PATCH 10/22] bindings: python: convert lines to offsets in LineRequest Vincent Fazio
@ 2024-10-08 13:19 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 13:19 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 8:57 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
> Remove `_check_line_name` in favor of a new function, `_line_to_offset`,
> that converts a line reference to an offset.
>
> This new function helps narrow types and simplifies the iteration logic
> that is used to build objects to interface with `_ext.Request`.
>
> Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
> ---
Looks good.
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 11/22] bindings: python: cast return value of LineRequest.get_values
2024-09-27 18:53 ` [libgpiod][PATCH 11/22] bindings: python: cast return value of LineRequest.get_values Vincent Fazio
@ 2024-10-08 13:20 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 13:20 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 8:57 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
> 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>
> ---
> 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 a1ca64cfd82c32be5de3fc53f6c981026911bb9c..917020b9ec7046dd8e10158f70efb555fc87eade 100644
> --- a/bindings/python/gpiod/line_request.py
> +++ b/bindings/python/gpiod/line_request.py
> @@ -122,7 +122,7 @@ class LineRequest:
>
> offsets = [self._line_to_offset(line) for line in lines]
>
> - buf = [None] * len(lines)
> + buf = cast(list[Value], [None] * len(offsets))
>
> self._req.get_values(offsets, buf)
> return buf
>
> --
> 2.34.1
>
I think this is the first time in this series where I understand what
cast() really does. Looks good.
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 12/22] bindings: python: raise exception type, not exception instance
2024-09-27 18:53 ` [libgpiod][PATCH 12/22] bindings: python: raise exception type, not exception instance Vincent Fazio
@ 2024-10-08 13:23 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 13:23 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 8:57 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
> This resolves a strict no-untyped-call mypy warning.
>
> Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
> ---
Ok, so I see this is how it's done in the standard library but why? If
an error doesn't take arguments, one should raise its type? Could you
elaborate more in the commit message?
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 13/22] bindings: python: selectively use f-strings
2024-09-27 18:53 ` [libgpiod][PATCH 13/22] bindings: python: selectively use f-strings Vincent Fazio
@ 2024-10-08 13:24 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 13:24 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 8:57 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
> Dataclasses are not migrated to f-strings so readability isn't impacted.
Could you add some details on what f-strings are and why they're preferred?
>
> def __str__(self) -> str:
> - return '<LineInfo offset={} name="{}" used={} consumer="{}" direction={} active_low={} bias={} drive={} edge_detection={} event_clock={} debounced={} debounce_period={}>'.format(
> + return '<LineInfo offset={} name="{}" used={} consumer="{}" direction={} active_low={} bias={} drive={} edge_detection={} event_clock={} debounced={} debounce_period={}>'.format( # noqa: UP032
I guess the comment tells the analyzers to ignore this? Maybe mention
that too in the commit message?
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 14/22] bindings: python: tests: fix duplicate test name
2024-09-27 18:53 ` [libgpiod][PATCH 14/22] bindings: python: tests: fix duplicate test name Vincent Fazio
@ 2024-10-08 13:25 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 13:25 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 8:57 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
> Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
> ---
> bindings/python/tests/tests_edge_event.py | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/bindings/python/tests/tests_edge_event.py b/bindings/python/tests/tests_edge_event.py
> index 17b27026356be60b6e928cff04917f487947824c..68ab17eae7be301cbca8d6d83f90a03df0aeea53 100644
> --- a/bindings/python/tests/tests_edge_event.py
> +++ b/bindings/python/tests/tests_edge_event.py
> @@ -118,7 +118,7 @@ class WaitingForEdgeEvents(TestCase):
>
> self.assertFalse(req.wait_edge_events(timedelta(microseconds=10000)))
>
> - def test_rising_edge_event(self):
> + def test_falling_edge_event(self):
> with gpiod.request_lines(
> self.sim.dev_path, {6: gpiod.LineSettings(edge_detection=Edge.FALLING)}
> ) as req:
>
> --
> 2.34.1
>
+commit message and LGTM
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 15/22] bindings: python: tests: clean up imports and exports
2024-09-27 18:53 ` [libgpiod][PATCH 15/22] bindings: python: tests: clean up imports and exports Vincent Fazio
@ 2024-10-08 13:27 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 13:27 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 8:57 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
I'm going to nag you again for the commit message but I think it's
important to say what exactly you're improving here (ordering, remove
unneeded gpiosim import, etc.). The patch otherwise looks good to me.
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 16/22] bindings: python: tests: make EventType private to prevent export
2024-09-27 18:53 ` [libgpiod][PATCH 16/22] bindings: python: tests: make EventType private to prevent export Vincent Fazio
@ 2024-10-08 13:29 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 13:29 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 8:57 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
> Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
> ---
> bindings/python/tests/tests_edge_event.py | 14 +++++++-------
> bindings/python/tests/tests_info_event.py | 10 +++++-----
> 2 files changed, 12 insertions(+), 12 deletions(-)
>
Makes sense! LGTM
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 17/22] bindings: python: tests: add type stubs for external modules
2024-09-27 18:53 ` [libgpiod][PATCH 17/22] bindings: python: tests: add type stubs for external modules Vincent Fazio
@ 2024-10-08 13:30 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 13:30 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 8:57 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
> Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
Some details on what it is and what it does please.
> ---
> bindings/python/tests/gpiosim/_ext.pyi | 21 +++++++++++++++++++++
> bindings/python/tests/procname/_ext.pyi | 1 +
> 2 files changed, 22 insertions(+)
>
> diff --git a/bindings/python/tests/gpiosim/_ext.pyi b/bindings/python/tests/gpiosim/_ext.pyi
> new file mode 100644
> index 0000000000000000000000000000000000000000..69d4b63cf54af25f9f029a68d36a9a63789ce132
> --- /dev/null
> +++ b/bindings/python/tests/gpiosim/_ext.pyi
> @@ -0,0 +1,21 @@
> +class Chip:
> + def __init__(self) -> None: ...
> + def set_label(self, label: str) -> None: ...
> + def set_num_lines(self, num_lines: int) -> None: ...
> + def set_line_name(self, offset: int, name: str) -> None: ...
> + def set_hog(self, offset: int, name: str, direction: int) -> None: ...
> + def enable(self) -> None: ...
> + def get_value(set, offset: int) -> int: ...
> + def set_pull(set, offset: int, pull: int) -> None: ...
> + @property
> + def dev_path(self) -> str: ...
> + @property
> + def name(self) -> str: ...
> +
Four spaces indents for consistency?
> +PULL_DOWN: int
> +PULL_UP: int
> +VALUE_INACTIVE: int
> +VALUE_ACTIVE: int
> +DIRECTION_INPUT: int
> +DIRECTION_OUTPUT_HIGH: int
> +DIRECTION_OUTPUT_LOW: int
> diff --git a/bindings/python/tests/procname/_ext.pyi b/bindings/python/tests/procname/_ext.pyi
> new file mode 100644
> index 0000000000000000000000000000000000000000..fdcd8ac15f2a0cb9b900ef272b2a10818c8eef4e
> --- /dev/null
> +++ b/bindings/python/tests/procname/_ext.pyi
> @@ -0,0 +1 @@
> +def set_process_name(name: str) -> None: ...
>
> --
> 2.34.1
>
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 18/22] bindings: python: tests: add missing type annotations
2024-09-27 18:53 ` [libgpiod][PATCH 18/22] bindings: python: tests: add missing type annotations Vincent Fazio
@ 2024-10-08 13:32 ` Bartosz Golaszewski
2024-10-09 16:41 ` Vincent Fazio
0 siblings, 1 reply; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 13:32 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 8:57 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
> Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
> ---
> bindings/python/tests/helpers.py | 6 +-
> bindings/python/tests/tests_chip.py | 68 +++++-----
> bindings/python/tests/tests_chip_info.py | 14 +-
> bindings/python/tests/tests_edge_event.py | 32 ++---
> bindings/python/tests/tests_info_event.py | 38 +++---
> bindings/python/tests/tests_line.py | 2 +-
> bindings/python/tests/tests_line_info.py | 22 ++--
> bindings/python/tests/tests_line_request.py | 184 +++++++++++++--------------
> bindings/python/tests/tests_line_settings.py | 12 +-
> bindings/python/tests/tests_module.py | 20 +--
> 10 files changed, 200 insertions(+), 198 deletions(-)
>
> diff --git a/bindings/python/tests/helpers.py b/bindings/python/tests/helpers.py
> index f9a15e8e33f62ad63923bddedc206022eabe96b4..d327da2816594655cec5a76e024e31ff978d5d93 100644
> --- a/bindings/python/tests/helpers.py
> +++ b/bindings/python/tests/helpers.py
> @@ -5,12 +5,12 @@ import os
>
>
> class LinkGuard:
> - def __init__(self, src, dst):
> + def __init__(self, src: str, dst: str) -> None:
> self.src = src
> self.dst = dst
>
> - def __enter__(self):
> + def __enter__(self) -> None:
> os.symlink(self.src, self.dst)
>
> - def __exit__(self, type, val, tb):
> + def __exit__(self, type, val, tb) -> None: # type: ignore[no-untyped-def]
> os.unlink(self.dst)
> diff --git a/bindings/python/tests/tests_chip.py b/bindings/python/tests/tests_chip.py
> index 9110bebf3596557fbacb3c7620e931982f9dc957..9c8f87579469e684ed3b6a5dbcef35e0856127ba 100644
> --- a/bindings/python/tests/tests_chip.py
> +++ b/bindings/python/tests/tests_chip.py
> @@ -12,19 +12,19 @@ from .helpers import LinkGuard
>
>
> class ChipConstructor(TestCase):
> - def test_open_existing_chip(self):
> + def test_open_existing_chip(self) -> None:
> sim = gpiosim.Chip()
>
I admit I don't know any better but does it really make sense to do it
for individual test cases?
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 19/22] bindings: python: tests: ignore purposeful type errors
2024-09-27 18:53 ` [libgpiod][PATCH 19/22] bindings: python: tests: ignore purposeful type errors Vincent Fazio
@ 2024-10-08 13:33 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 13:33 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 8:57 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
> Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
> ---
> bindings/python/tests/tests_chip.py | 12 ++++++------
> bindings/python/tests/tests_chip_info.py | 6 +++---
> bindings/python/tests/tests_info_event.py | 12 ++++++------
> bindings/python/tests/tests_line_info.py | 2 +-
> bindings/python/tests/tests_line_request.py | 16 ++++++++--------
> bindings/python/tests/tests_module.py | 6 +++---
> 6 files changed, 27 insertions(+), 27 deletions(-)
I need the commit message here because I have no idea what this change does. :(
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 20/22] bindings: python: tests: annotate internal members
2024-09-27 18:53 ` [libgpiod][PATCH 20/22] bindings: python: tests: annotate internal members Vincent Fazio
@ 2024-10-08 13:34 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 13:34 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 8:57 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
> Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
> ---
> bindings/python/tests/tests_chip.py | 10 +++++++---
> bindings/python/tests/tests_chip_info.py | 13 ++++++++++---
> bindings/python/tests/tests_edge_event.py | 11 +++++++++--
> bindings/python/tests/tests_info_event.py | 30 +++++++++++++++++++++++++-----
> bindings/python/tests/tests_line_info.py | 13 +++++++++++--
> 5 files changed, 62 insertions(+), 15 deletions(-)
>
> diff --git a/bindings/python/tests/tests_chip.py b/bindings/python/tests/tests_chip.py
> index 89d5df4341eceefbc0eed9b880ac641caa682af5..b719f6ba402c962b3ba8029cef61ed28fd1a525a 100644
> --- a/bindings/python/tests/tests_chip.py
> +++ b/bindings/python/tests/tests_chip.py
> @@ -3,6 +3,7 @@
>
> import errno
> import os
> +from typing import Optional
> from unittest import TestCase
>
> import gpiod
> @@ -70,7 +71,7 @@ class ChipBooleanConversion(TestCase):
>
> class ChipProperties(TestCase):
> def setUp(self) -> None:
> - self.sim = gpiosim.Chip()
> + self.sim: Optional[gpiosim.Chip] = gpiosim.Chip()
> self.chip = gpiod.Chip(self.sim.dev_path)
>
> def tearDown(self) -> None:
> @@ -78,6 +79,7 @@ class ChipProperties(TestCase):
> self.sim = None
>
> def test_get_chip_path(self) -> None:
> + assert self.sim
Please say in the commit message why this is needed because I don't
understand this line and others below.
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 21/22] bindings: python: tests: use f-strings
2024-09-27 18:53 ` [libgpiod][PATCH 21/22] bindings: python: tests: use f-strings Vincent Fazio
@ 2024-10-08 13:35 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 13:35 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 8:57 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
> Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
> ---
> bindings/python/tests/__init__.py | 4 +---
> bindings/python/tests/tests_chip.py | 10 ++++------
> bindings/python/tests/tests_chip_info.py | 2 +-
> bindings/python/tests/tests_line_request.py | 4 +---
> bindings/python/tests/tests_module.py | 4 ++--
> 5 files changed, 9 insertions(+), 15 deletions(-)
>
Looks good.
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 22/22] bindings: python: configure and document dev dependencies
2024-09-27 18:53 ` [libgpiod][PATCH 22/22] bindings: python: configure and document dev dependencies Vincent Fazio
@ 2024-10-08 13:35 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 13:35 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 8:57 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
> Mypy [0] is a popular static type checker that validates attribute and
> variable use and ensures function arguments adhere to type annotations.
>
> Ruff [1] is a popular Rust-based Python linter and code formatter. It
> has support for a large set of linting rules [2] and largely complies
> with the Black format [3].
>
> Add documentation to the README for how to run the tools.
>
> [0]: https://mypy.readthedocs.io/en/stable/
> [1]: https://docs.astral.sh/ruff/
> [2]: https://docs.astral.sh/ruff/rules/
> [3]: https://docs.astral.sh/ruff/formatter/#black-compatibility
> Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
> ---
> bindings/python/README.md | 17 +++++++++++++++++
> bindings/python/pyproject.toml | 36 ++++++++++++++++++++++++++++++++++++
> 2 files changed, 53 insertions(+)
>
> diff --git a/bindings/python/README.md b/bindings/python/README.md
> index cb5cee62cc46980ce2484bc85d8686ffb8622e59..89c824cebbd735624159a5b30a8bbee2c55e896e 100644
> --- a/bindings/python/README.md
> +++ b/bindings/python/README.md
> @@ -112,3 +112,20 @@ make python-tests-run
>
> from the `libgpiod/bindings/python` directory as root (necessary to be able
> to create the **gpio-sims** used for testing).
> +
> +## Linting/Formatting
> +
> +When making changes, ensure type checks and linting still pass:
> +
> +```
> +python3 -m venv venv
> +. venv/bin/activate
> +pip install mypy ruff
> +mypy; ruff format; ruff check
> +```
> +
> +Ideally the gpiod library will continue to pass strict checks:
> +
> +```
> +mypy --strict
> +```
> \ No newline at end of file
> diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml
> index f6bf43c0a20edc76bfa51a98e7d523c8dadefea1..43e85a72daaea50c07a527d7b388ac9a4396a3d8 100644
> --- a/bindings/python/pyproject.toml
> +++ b/bindings/python/pyproject.toml
> @@ -3,3 +3,39 @@
>
> [build-system]
> requires = ["setuptools", "wheel", "packaging"]
> +
> +[tool.mypy]
> +python_version = "3.9"
> +files = [
> + "gpiod/",
> + "tests/",
> +]
> +
> +[[tool.mypy.overrides]]
> +module = "gpiod.line.*"
> +strict_equality = false # Ignore Enum comparison-overlap https://github.com/python/mypy/issues/17317
> +
> +[tool.ruff]
> +target-version = "py39"
> +include = [
> + "gpiod/**/*.py",
> + "gpiod/**/*.pyi",
> + "tests/**/*.py",
> + "tests/**/*.pyi",
> +]
> +
> +[tool.ruff.lint]
> +select = ["B", "E", "F", "I", "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",
> + # Ignore new Union (|) syntax until we require 3.10+
> + "UP007",
> +]
> +
> +[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
> \ No newline at end of file
>
> --
> 2.34.1
>
LGTM
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
` (21 preceding siblings ...)
2024-09-27 18:53 ` [libgpiod][PATCH 22/22] bindings: python: configure and document dev dependencies Vincent Fazio
@ 2024-10-08 13:37 ` Bartosz Golaszewski
22 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 13:37 UTC (permalink / raw)
To: Vincent Fazio; +Cc: linux-gpio, vfazio
On Fri, Sep 27, 2024 at 9:05 PM Vincent Fazio <vfazio@xes-inc.com> wrote:
>
> This patch series employs mypy [0] and ruff [1] to ensure the gpiod
> library has correctly typed public interfaces, is performing proper type
> checking internally, is consistently formatted in a standard code style
> that targets Python 3.9 syntax, and passes a subset of linting checks.
>
> Patches 1 and 2 remove unused imports, sort the remainder, and ensure
> the publicly usable classes are available from the gpiod base module.
>
> Patches 3 and 4 fix and add annotations to the gpiod bindings.
>
> Patches 5-13 fix type and lint errors internal to the bindings.
>
> Patch 14 fixes a duplicate test name identified by the linter.
>
> Patch 15 and 16 remove unused imports, sort the remainder, and fix lint
> errors related to a shadowed export.
>
> Patches 17 and 18 fix and add annotations to the test gpiod bindings.
>
> Patches 19-21 fix type and lint errors internal to the tests.
>
> Patch 22 adds mypy and ruff configuration to pyproject.toml and adds
> documentation to the readme so future patches can be evaluated against a
> standard set of rules.
>
> There should be no functional changes that impact existing code as part
> of this series.
>
> All unit tests continue to pass without changes and code coverage has
> not changed.
>
> After this series is applied, the public type annotations will reflect
> the argument expectations of the class methods so consumers can type
> check their code against the gpiod type annotations.
>
> [0]: https://mypy.readthedocs.io/en/stable/
> [1]: https://docs.astral.sh/ruff/
>
> Signed-off-by: Vincent Fazio <vfazio@xes-inc.com>
> ---
Phew! Nice work!
My main concern is the lack of proper commit messages which makes some
of the changes confusing to me - an intermediate python developer.
I added some other requests, some commits will need splitting into two
but overall this looks nice and I'll be happy to pick it up.
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 07/22] bindings: python: fix Chip union-attr type errors
2024-10-08 13:16 ` Bartosz Golaszewski
@ 2024-10-08 14:57 ` Vincent Fazio
2024-10-08 15:46 ` Bartosz Golaszewski
0 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-10-08 14:57 UTC (permalink / raw)
To: Bartosz Golaszewski; +Cc: Vincent Fazio, linux-gpio
On Tue, Oct 8, 2024 at 8:16 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
>
> Ok, so I don't really understand what is happening here. We're going
> to re-assign _chip in every function? What happens to cast() if _chip
> IS None?
In this scenario, self._chip cannot be None. The self._check_closed() guard
ensures this, however, type checkers (at least mypy) cannot infer that from the
current code pattern.
`cast` is informing the type checker that past this point, self._chip should
not be considered as None and it's safe to reference attributes off the object
This seemed like the cleanest alternative, though others are:
* use a local variable for the cast result. This may be less confusing but
incurs more changed lines
self._check_closed()
chip = cast(_ext.Chip, self._chip)
return chip.path
* use asserts. These aren't always enforced during runtime so we cannot replace
_check_closed but it does inform the type checker that it can narrow the type.
Using both is ok, just slightly redundant.
self._check_closed()
assert self._chip is not None
return self._chip.path
* add a `if self._chip is None` check that duplicates _check_closed
(or replace it completely)
* other "creative" solutions like a wrapper that returns a Chip or
throws an exception if it's None.
def _chip_or_exc(self) -> Chip:
if self._chip is None:
raise Exception
return self._chip
chip = self._chip_or_exc()
return chip.path
>
> Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 07/22] bindings: python: fix Chip union-attr type errors
2024-10-08 14:57 ` Vincent Fazio
@ 2024-10-08 15:46 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-08 15:46 UTC (permalink / raw)
To: Vincent Fazio; +Cc: Vincent Fazio, linux-gpio
On Tue, Oct 8, 2024 at 4:57 PM Vincent Fazio <vfazio@gmail.com> wrote:
>
> On Tue, Oct 8, 2024 at 8:16 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> >
> >
> > Ok, so I don't really understand what is happening here. We're going
> > to re-assign _chip in every function? What happens to cast() if _chip
> > IS None?
>
> In this scenario, self._chip cannot be None. The self._check_closed() guard
> ensures this, however, type checkers (at least mypy) cannot infer that from the
> current code pattern.
>
> `cast` is informing the type checker that past this point, self._chip should
> not be considered as None and it's safe to reference attributes off the object
>
> This seemed like the cleanest alternative, though others are:
>
> * use a local variable for the cast result. This may be less confusing but
> incurs more changed lines
>
> self._check_closed()
> chip = cast(_ext.Chip, self._chip)
> return chip.path
>
For the sake of readability, I would lean more towards this option if
I'm honest.
Or even - if you need to use the cast variable only once:
self._check_closed()
return cast(_ext.Chip, self._chip).path
?
> * use asserts. These aren't always enforced during runtime so we cannot replace
> _check_closed but it does inform the type checker that it can narrow the type.
> Using both is ok, just slightly redundant.
>
> self._check_closed()
> assert self._chip is not None
> return self._chip.path
>
Yeah, this isn't optimal.
> * add a `if self._chip is None` check that duplicates _check_closed
> (or replace it completely)
>
Yep, no.
> * other "creative" solutions like a wrapper that returns a Chip or
> throws an exception if it's None.
>
> def _chip_or_exc(self) -> Chip:
> if self._chip is None:
> raise Exception
> return self._chip
>
> chip = self._chip_or_exc()
> return chip.path
>
Ugh. I see, cast() is the best solution.
Please consider the small change I suggested.
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 18/22] bindings: python: tests: add missing type annotations
2024-10-08 13:32 ` Bartosz Golaszewski
@ 2024-10-09 16:41 ` Vincent Fazio
2024-10-09 18:24 ` Bartosz Golaszewski
0 siblings, 1 reply; 50+ messages in thread
From: Vincent Fazio @ 2024-10-09 16:41 UTC (permalink / raw)
To: Bartosz Golaszewski; +Cc: Vincent Fazio, linux-gpio
On Tue, Oct 8, 2024 at 8:32 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
>
> I admit I don't know any better but does it really make sense to do it
> for individual test cases?
Some projects type their tests while others don't make it a priority. The way I
see it, the overhead is minimal when adding a new test so why not add it.
One of the caveats is that mypy does not type check the bodies of functions
that have untyped function definitions. So:
def _internal_fn(arg: str) -> str:
return arg
def test_fn(): # will not be type checked by default
_internal_fn(10) # so this will not raise a type error
It seems important to ensure the test cases are either abiding by the typed
library interface or knowingly using invalid arguments to test "negative" cases
(type errors which are suppressed in patch 19) for callers who do not leverage
or ignore the library's type annotations.
When fixing the type annotations for gpiod, I used the tests and examples as a
reference for what the call interface is expected to support.
For the situation above re untyped function definitions, mypy does have a knob
that allows type checking the bodies of untyped functions. If we used that, it
could be argued that the majority of this patch could be dropped.
So, I guess some questions:
Do you want the test suite type checked?
If not, a lot of the patches touching tests can be dropped
If you do, to what degree? Do you want function bodies type checked?
For example, mypy identified the problems in patch 14 and 16. Even if untyped
functions aren't checked, those problems would still have been flagged.
If you think there's value in type checking functions, do you want to use
explicitly typed function signatures or leverage `check_untyped_defs` [0] (this
could be added to the mypy configuration in pyproject.toml).
>
> Bart
[0]: https://mypy.readthedocs.io/en/stable/command_line.html#cmdoption-mypy-check-untyped-defs
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [libgpiod][PATCH 18/22] bindings: python: tests: add missing type annotations
2024-10-09 16:41 ` Vincent Fazio
@ 2024-10-09 18:24 ` Bartosz Golaszewski
0 siblings, 0 replies; 50+ messages in thread
From: Bartosz Golaszewski @ 2024-10-09 18:24 UTC (permalink / raw)
To: Vincent Fazio; +Cc: Vincent Fazio, linux-gpio
On Wed, Oct 9, 2024 at 6:41 PM Vincent Fazio <vfazio@gmail.com> wrote:
>
> On Tue, Oct 8, 2024 at 8:32 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> >
> >
> > I admit I don't know any better but does it really make sense to do it
> > for individual test cases?
>
> Some projects type their tests while others don't make it a priority. The way I
> see it, the overhead is minimal when adding a new test so why not add it.
>
> One of the caveats is that mypy does not type check the bodies of functions
> that have untyped function definitions. So:
>
> def _internal_fn(arg: str) -> str:
> return arg
>
> def test_fn(): # will not be type checked by default
> _internal_fn(10) # so this will not raise a type error
>
> It seems important to ensure the test cases are either abiding by the typed
> library interface or knowingly using invalid arguments to test "negative" cases
> (type errors which are suppressed in patch 19) for callers who do not leverage
> or ignore the library's type annotations.
>
> When fixing the type annotations for gpiod, I used the tests and examples as a
> reference for what the call interface is expected to support.
>
> For the situation above re untyped function definitions, mypy does have a knob
> that allows type checking the bodies of untyped functions. If we used that, it
> could be argued that the majority of this patch could be dropped.
>
> So, I guess some questions:
>
> Do you want the test suite type checked?
>
Yes, you've already done most of the work, so I'm all in favor of
keeping it. I see value in having everything typed and I don't expect
to be writing a lot of new tests so it won't involve much overhead.
> If not, a lot of the patches touching tests can be dropped
>
> If you do, to what degree? Do you want function bodies type checked?
>
I take it your changes already do it? Sure, let's keep it.
> For example, mypy identified the problems in patch 14 and 16. Even if untyped
> functions aren't checked, those problems would still have been flagged.
>
> If you think there's value in type checking functions, do you want to use
> explicitly typed function signatures or leverage `check_untyped_defs` [0] (this
> could be added to the mypy configuration in pyproject.toml).
>
Thanks,
Bart
^ permalink raw reply [flat|nested] 50+ messages in thread
end of thread, other threads:[~2024-10-09 18:24 UTC | newest]
Thread overview: 50+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-27 18:53 [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Vincent Fazio
2024-09-27 18:53 ` [libgpiod][PATCH 01/22] bindings: python: clean up imports and exports Vincent Fazio
2024-10-08 11:16 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 02/22] bindings: python: make internal a private submodule Vincent Fazio
2024-10-08 11:24 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 03/22] bindings: python: fix annotation of variable length tuples Vincent Fazio
2024-10-08 13:02 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 04/22] bindings: python: add missing method type annotations Vincent Fazio
2024-10-08 13:07 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 05/22] bindings: python: add type stubs for _ext Vincent Fazio
2024-10-08 13:08 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 06/22] bindings: python: annotate internal members of Chip Vincent Fazio
2024-10-08 13:09 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 07/22] bindings: python: fix Chip union-attr type errors Vincent Fazio
2024-10-08 13:16 ` Bartosz Golaszewski
2024-10-08 14:57 ` Vincent Fazio
2024-10-08 15:46 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 08/22] bindings: python: annotate internal members of LineRequest Vincent Fazio
2024-10-08 13:17 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 09/22] bindings: python: fix LineRequest union-attr type errors Vincent Fazio
2024-10-08 13:18 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 10/22] bindings: python: convert lines to offsets in LineRequest Vincent Fazio
2024-10-08 13:19 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 11/22] bindings: python: cast return value of LineRequest.get_values Vincent Fazio
2024-10-08 13:20 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 12/22] bindings: python: raise exception type, not exception instance Vincent Fazio
2024-10-08 13:23 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 13/22] bindings: python: selectively use f-strings Vincent Fazio
2024-10-08 13:24 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 14/22] bindings: python: tests: fix duplicate test name Vincent Fazio
2024-10-08 13:25 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 15/22] bindings: python: tests: clean up imports and exports Vincent Fazio
2024-10-08 13:27 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 16/22] bindings: python: tests: make EventType private to prevent export Vincent Fazio
2024-10-08 13:29 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 17/22] bindings: python: tests: add type stubs for external modules Vincent Fazio
2024-10-08 13:30 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 18/22] bindings: python: tests: add missing type annotations Vincent Fazio
2024-10-08 13:32 ` Bartosz Golaszewski
2024-10-09 16:41 ` Vincent Fazio
2024-10-09 18:24 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 19/22] bindings: python: tests: ignore purposeful type errors Vincent Fazio
2024-10-08 13:33 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 20/22] bindings: python: tests: annotate internal members Vincent Fazio
2024-10-08 13:34 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 21/22] bindings: python: tests: use f-strings Vincent Fazio
2024-10-08 13:35 ` Bartosz Golaszewski
2024-09-27 18:53 ` [libgpiod][PATCH 22/22] bindings: python: configure and document dev dependencies Vincent Fazio
2024-10-08 13:35 ` Bartosz Golaszewski
2024-10-08 13:37 ` [libgpiod][PATCH 00/22] bindings: python: conform to mypy and ruff linter recommendations Bartosz Golaszewski
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).