All of lore.kernel.org
 help / color / mirror / Atom feed
From: Bartosz Golaszewski <brgl@bgdev.pl>
To: Kent Gibson <warthog618@gmail.com>,
	Linus Walleij <linus.walleij@linaro.org>,
	Andy Shevchenko <andriy.shevchenko@linux.intel.com>,
	Viresh Kumar <viresh.kumar@linaro.org>
Cc: linux-gpio@vger.kernel.org, Bartosz Golaszewski <brgl@bgdev.pl>
Subject: [libgpiod v2][PATCH v4 1/4] bindings: python: remove old version
Date: Wed, 26 Oct 2022 14:34:22 +0200	[thread overview]
Message-ID: <20221026123425.498912-2-brgl@bgdev.pl> (raw)
In-Reply-To: <20221026123425.498912-1-brgl@bgdev.pl>

This removes v1 python bindings for easier review of v2.

Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
---
 bindings/python/Makefile.am              |   25 -
 bindings/python/examples/Makefile.am     |   10 -
 bindings/python/examples/gpiodetect.py   |   16 -
 bindings/python/examples/gpiofind.py     |   20 -
 bindings/python/examples/gpioget.py      |   25 -
 bindings/python/examples/gpioinfo.py     |   28 -
 bindings/python/examples/gpiomon.py      |   42 -
 bindings/python/examples/gpioset.py      |   25 -
 bindings/python/gpiodmodule.c            | 2662 ----------------------
 bindings/python/tests/Makefile.am        |   13 -
 bindings/python/tests/gpiod_py_test.py   |  832 -------
 bindings/python/tests/gpiomockupmodule.c |  309 ---
 12 files changed, 4007 deletions(-)
 delete mode 100644 bindings/python/Makefile.am
 delete mode 100644 bindings/python/examples/Makefile.am
 delete mode 100755 bindings/python/examples/gpiodetect.py
 delete mode 100755 bindings/python/examples/gpiofind.py
 delete mode 100755 bindings/python/examples/gpioget.py
 delete mode 100755 bindings/python/examples/gpioinfo.py
 delete mode 100755 bindings/python/examples/gpiomon.py
 delete mode 100755 bindings/python/examples/gpioset.py
 delete mode 100644 bindings/python/gpiodmodule.c
 delete mode 100644 bindings/python/tests/Makefile.am
 delete mode 100755 bindings/python/tests/gpiod_py_test.py
 delete mode 100644 bindings/python/tests/gpiomockupmodule.c

diff --git a/bindings/python/Makefile.am b/bindings/python/Makefile.am
deleted file mode 100644
index 4405d8f..0000000
--- a/bindings/python/Makefile.am
+++ /dev/null
@@ -1,25 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-or-later
-# SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
-
-pyexec_LTLIBRARIES = gpiod.la
-
-gpiod_la_SOURCES = gpiodmodule.c
-
-gpiod_la_CFLAGS = -I$(top_srcdir)/include/
-gpiod_la_CFLAGS += -Wall -Wextra -g -std=gnu89 $(PYTHON_CPPFLAGS)
-gpiod_la_LDFLAGS = -module -avoid-version
-gpiod_la_LIBADD = $(top_builddir)/lib/libgpiod.la $(PYTHON_LIBS)
-
-SUBDIRS = .
-
-if WITH_TESTS
-
-SUBDIRS += tests
-
-endif
-
-if WITH_EXAMPLES
-
-SUBDIRS += examples
-
-endif
diff --git a/bindings/python/examples/Makefile.am b/bindings/python/examples/Makefile.am
deleted file mode 100644
index 4169469..0000000
--- a/bindings/python/examples/Makefile.am
+++ /dev/null
@@ -1,10 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-or-later
-# SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
-
-EXTRA_DIST =				\
-		gpiodetect.py		\
-		gpiofind.py		\
-		gpioget.py		\
-		gpioinfo.py		\
-		gpiomon.py		\
-		gpioset.py
diff --git a/bindings/python/examples/gpiodetect.py b/bindings/python/examples/gpiodetect.py
deleted file mode 100755
index da6ee9a..0000000
--- a/bindings/python/examples/gpiodetect.py
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-License-Identifier: GPL-2.0-or-later
-# SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
-
-'''Reimplementation of the gpiodetect tool in Python.'''
-
-import gpiod
-import os
-
-if __name__ == '__main__':
-    for entry in os.scandir('/dev/'):
-        if gpiod.is_gpiochip_device(entry.path):
-            with gpiod.Chip(entry.path) as chip:
-                print('{} [{}] ({} lines)'.format(chip.name(),
-                                                  chip.label(),
-                                                  chip.num_lines()))
diff --git a/bindings/python/examples/gpiofind.py b/bindings/python/examples/gpiofind.py
deleted file mode 100755
index a9ec734..0000000
--- a/bindings/python/examples/gpiofind.py
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-License-Identifier: GPL-2.0-or-later
-# SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
-
-'''Reimplementation of the gpiofind tool in Python.'''
-
-import gpiod
-import os
-import sys
-
-if __name__ == '__main__':
-    for entry in os.scandir('/dev/'):
-        if gpiod.is_gpiochip_device(entry.path):
-            with gpiod.Chip(entry.path) as chip:
-                offset = chip.find_line(sys.argv[1], unique=True)
-                if offset is not None:
-                     print('{} {}'.format(line.owner().name(), offset))
-                     sys.exit(0)
-
-    sys.exit(1)
diff --git a/bindings/python/examples/gpioget.py b/bindings/python/examples/gpioget.py
deleted file mode 100755
index 26a2ced..0000000
--- a/bindings/python/examples/gpioget.py
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-License-Identifier: GPL-2.0-or-later
-# SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
-
-'''Simplified reimplementation of the gpioget tool in Python.'''
-
-import gpiod
-import sys
-
-if __name__ == '__main__':
-    if len(sys.argv) < 3:
-        raise TypeError('usage: gpioget.py <gpiochip> <offset1> <offset2> ...')
-
-    with gpiod.Chip(sys.argv[1]) as chip:
-        offsets = []
-        for off in sys.argv[2:]:
-            offsets.append(int(off))
-
-        lines = chip.get_lines(offsets)
-        lines.request(consumer=sys.argv[0], type=gpiod.LINE_REQ_DIR_IN)
-        vals = lines.get_values()
-
-        for val in vals:
-            print(val, end=' ')
-        print()
diff --git a/bindings/python/examples/gpioinfo.py b/bindings/python/examples/gpioinfo.py
deleted file mode 100755
index 84188f1..0000000
--- a/bindings/python/examples/gpioinfo.py
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-License-Identifier: GPL-2.0-or-later
-# SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
-
-'''Simplified reimplementation of the gpioinfo tool in Python.'''
-
-import gpiod
-import os
-
-if __name__ == '__main__':
-    for entry in os.scandir('/dev/'):
-        if gpiod.is_gpiochip_device(entry.path):
-            with gpiod.Chip(entry.path) as chip:
-                print('{} - {} lines:'.format(chip.name(), chip.num_lines()))
-
-                for line in gpiod.LineIter(chip):
-                    offset = line.offset()
-                    name = line.name()
-                    consumer = line.consumer()
-                    direction = line.direction()
-                    active_low = line.is_active_low()
-
-                    print('\tline {:>3}: {:>18} {:>12} {:>8} {:>10}'.format(
-                          offset,
-                          'unnamed' if name is None else name,
-                          'unused' if consumer is None else consumer,
-                          'input' if direction == gpiod.Line.DIRECTION_INPUT else 'output',
-                          'active-low' if active_low else 'active-high'))
diff --git a/bindings/python/examples/gpiomon.py b/bindings/python/examples/gpiomon.py
deleted file mode 100755
index b29f3ce..0000000
--- a/bindings/python/examples/gpiomon.py
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-License-Identifier: GPL-2.0-or-later
-# SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
-
-'''Simplified reimplementation of the gpiomon tool in Python.'''
-
-import gpiod
-import sys
-
-if __name__ == '__main__':
-    def print_event(event):
-        if event.type == gpiod.LineEvent.RISING_EDGE:
-            evstr = ' RISING EDGE'
-        elif event.type == gpiod.LineEvent.FALLING_EDGE:
-            evstr = 'FALLING EDGE'
-        else:
-            raise TypeError('Invalid event type')
-
-        print('event: {} offset: {} timestamp: [{}.{}]'.format(evstr,
-                                                               event.source.offset(),
-                                                               event.sec, event.nsec))
-
-    if len(sys.argv) < 3:
-        raise TypeError('usage: gpiomon.py <gpiochip> <offset1> <offset2> ...')
-
-    with gpiod.Chip(sys.argv[1]) as chip:
-        offsets = []
-        for off in sys.argv[2:]:
-            offsets.append(int(off))
-
-        lines = chip.get_lines(offsets)
-        lines.request(consumer=sys.argv[0], type=gpiod.LINE_REQ_EV_BOTH_EDGES)
-
-        try:
-            while True:
-                ev_lines = lines.event_wait(sec=1)
-                if ev_lines:
-                    for line in ev_lines:
-                        event = line.event_read()
-                        print_event(event)
-        except KeyboardInterrupt:
-            sys.exit(130)
diff --git a/bindings/python/examples/gpioset.py b/bindings/python/examples/gpioset.py
deleted file mode 100755
index 63e08dc..0000000
--- a/bindings/python/examples/gpioset.py
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-License-Identifier: GPL-2.0-or-later
-# SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
-
-'''Simplified reimplementation of the gpioset tool in Python.'''
-
-import gpiod
-import sys
-
-if __name__ == '__main__':
-    if len(sys.argv) < 3:
-        raise TypeError('usage: gpioset.py <gpiochip> <offset1>=<value1> ...')
-
-    with gpiod.Chip(sys.argv[1]) as chip:
-        offsets = []
-        values = []
-        for arg in sys.argv[2:]:
-            arg = arg.split('=')
-            offsets.append(int(arg[0]))
-            values.append(int(arg[1]))
-
-        lines = chip.get_lines(offsets)
-        lines.request(consumer=sys.argv[0], type=gpiod.LINE_REQ_DIR_OUT)
-        lines.set_values(values)
-        input()
diff --git a/bindings/python/gpiodmodule.c b/bindings/python/gpiodmodule.c
deleted file mode 100644
index ed039e4..0000000
--- a/bindings/python/gpiodmodule.c
+++ /dev/null
@@ -1,2662 +0,0 @@
-// SPDX-License-Identifier: LGPL-2.1-or-later
-// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
-
-#include <Python.h>
-#include <gpiod.h>
-
-#define LINE_REQUEST_MAX_LINES 64
-
-typedef struct {
-	PyObject_HEAD;
-	struct gpiod_chip *chip;
-} gpiod_ChipObject;
-
-typedef struct {
-	PyObject_HEAD;
-	struct gpiod_line *line;
-	gpiod_ChipObject *owner;
-} gpiod_LineObject;
-
-typedef struct {
-	PyObject_HEAD;
-	struct gpiod_line_event event;
-	gpiod_LineObject *source;
-} gpiod_LineEventObject;
-
-typedef struct {
-	PyObject_HEAD;
-	PyObject **lines;
-	Py_ssize_t num_lines;
-	Py_ssize_t iter_idx;
-} gpiod_LineBulkObject;
-
-typedef struct {
-	PyObject_HEAD;
-	unsigned int offset;
-	gpiod_ChipObject *owner;
-} gpiod_LineIterObject;
-
-static gpiod_LineBulkObject *gpiod_LineToLineBulk(gpiod_LineObject *line);
-static gpiod_LineObject *gpiod_MakeLineObject(gpiod_ChipObject *owner,
-					      struct gpiod_line *line);
-
-enum {
-	gpiod_LINE_REQ_DIR_AS_IS = 1,
-	gpiod_LINE_REQ_DIR_IN,
-	gpiod_LINE_REQ_DIR_OUT,
-	gpiod_LINE_REQ_EV_FALLING_EDGE,
-	gpiod_LINE_REQ_EV_RISING_EDGE,
-	gpiod_LINE_REQ_EV_BOTH_EDGES,
-};
-
-enum {
-	gpiod_LINE_REQ_FLAG_OPEN_DRAIN		= GPIOD_BIT(0),
-	gpiod_LINE_REQ_FLAG_OPEN_SOURCE		= GPIOD_BIT(1),
-	gpiod_LINE_REQ_FLAG_ACTIVE_LOW		= GPIOD_BIT(2),
-	gpiod_LINE_REQ_FLAG_BIAS_DISABLED	= GPIOD_BIT(3),
-	gpiod_LINE_REQ_FLAG_BIAS_PULL_DOWN	= GPIOD_BIT(4),
-	gpiod_LINE_REQ_FLAG_BIAS_PULL_UP	= GPIOD_BIT(5),
-};
-
-enum {
-	gpiod_DIRECTION_INPUT = 1,
-	gpiod_DIRECTION_OUTPUT,
-};
-
-enum {
-	gpiod_DRIVE_PUSH_PULL,
-	gpiod_DRIVE_OPEN_DRAIN,
-	gpiod_DRIVE_OPEN_SOURCE,
-};
-
-enum {
-	gpiod_BIAS_UNKNOWN = 1,
-	gpiod_BIAS_DISABLED,
-	gpiod_BIAS_PULL_UP,
-	gpiod_BIAS_PULL_DOWN,
-};
-
-enum {
-	gpiod_RISING_EDGE = 1,
-	gpiod_FALLING_EDGE,
-};
-
-static bool gpiod_ChipIsClosed(gpiod_ChipObject *chip)
-{
-	if (!chip->chip) {
-		PyErr_SetString(PyExc_ValueError,
-				"I/O operation on closed file");
-		return true;
-	}
-
-	return false;
-}
-
-static PyObject *gpiod_CallMethodPyArgs(PyObject *obj, const char *method,
-					PyObject *args, PyObject *kwds)
-{
-	PyObject *callable, *ret;
-
-	callable = PyObject_GetAttrString((PyObject *)obj, method);
-	if (!callable)
-		return NULL;
-
-	ret = PyObject_Call(callable, args, kwds);
-	Py_DECREF(callable);
-
-	return ret;
-}
-
-static int gpiod_LineEvent_init(PyObject *Py_UNUSED(ignored0),
-				PyObject *Py_UNUSED(ignored1),
-				PyObject *Py_UNUSED(ignored2))
-{
-	PyErr_SetString(PyExc_NotImplementedError,
-			"Only gpiod.Line can create new LineEvent objects.");
-	return -1;
-}
-
-static void gpiod_LineEvent_dealloc(gpiod_LineEventObject *self)
-{
-	if (self->source)
-		Py_DECREF(self->source);
-
-	PyObject_Del(self);
-}
-
-PyDoc_STRVAR(gpiod_LineEvent_get_type_doc,
-"Event type of this line event (integer).");
-
-PyObject *gpiod_LineEvent_get_type(gpiod_LineEventObject *self,
-				   PyObject *Py_UNUSED(ignored))
-{
-	int rv;
-
-	if (self->event.event_type == GPIOD_LINE_EVENT_RISING_EDGE)
-		rv = gpiod_RISING_EDGE;
-	else
-		rv = gpiod_FALLING_EDGE;
-
-	return Py_BuildValue("I", rv);
-}
-
-PyDoc_STRVAR(gpiod_LineEvent_get_sec_doc,
-"Seconds value of the line event timestamp (integer).");
-
-PyObject *gpiod_LineEvent_get_sec(gpiod_LineEventObject *self,
-				  PyObject *Py_UNUSED(ignored))
-{
-	return Py_BuildValue("I", self->event.ts.tv_sec);
-}
-
-PyDoc_STRVAR(gpiod_LineEvent_get_nsec_doc,
-"Nanoseconds value of the line event timestamp (integer).");
-
-PyObject *gpiod_LineEvent_get_nsec(gpiod_LineEventObject *self,
-				   PyObject *Py_UNUSED(ignored))
-{
-	return Py_BuildValue("I", self->event.ts.tv_nsec);
-}
-
-PyDoc_STRVAR(gpiod_LineEvent_get_source_doc,
-"Line object representing the GPIO line on which this event\n"
-"occurred (gpiod.Line object).");
-
-gpiod_LineObject *gpiod_LineEvent_get_source(gpiod_LineEventObject *self,
-					     PyObject *Py_UNUSED(ignored))
-{
-	Py_INCREF(self->source);
-	return self->source;
-}
-
-static PyGetSetDef gpiod_LineEvent_getset[] = {
-	{
-		.name = "type",
-		.get = (getter)gpiod_LineEvent_get_type,
-		.doc = gpiod_LineEvent_get_type_doc,
-	},
-	{
-		.name = "sec",
-		.get = (getter)gpiod_LineEvent_get_sec,
-		.doc = gpiod_LineEvent_get_sec_doc,
-	},
-	{
-		.name = "nsec",
-		.get = (getter)gpiod_LineEvent_get_nsec,
-		.doc = gpiod_LineEvent_get_nsec_doc,
-	},
-	{
-		.name = "source",
-		.get = (getter)gpiod_LineEvent_get_source,
-		.doc = gpiod_LineEvent_get_source_doc,
-	},
-	{ }
-};
-
-static PyObject *gpiod_LineEvent_repr(gpiod_LineEventObject *self)
-{
-	PyObject *line_repr, *ret;
-	const char *edge;
-
-	if (self->event.event_type == GPIOD_LINE_EVENT_RISING_EDGE)
-		edge = "RISING EDGE";
-	else
-		edge = "FALLING EDGE";
-
-	line_repr = PyObject_CallMethod((PyObject *)self->source,
-					"__repr__", "");
-
-	ret = PyUnicode_FromFormat("'%s (%ld.%ld) source(%S)'",
-				   edge, self->event.ts.tv_sec,
-				   self->event.ts.tv_nsec, line_repr);
-	Py_DECREF(line_repr);
-
-	return ret;
-}
-
-PyDoc_STRVAR(gpiod_LineEventType_doc,
-"Represents a single GPIO line event. This object is immutable and can only\n"
-"be created by an instance of gpiod.Line.");
-
-static PyTypeObject gpiod_LineEventType = {
-	PyVarObject_HEAD_INIT(NULL, 0)
-	.tp_name = "gpiod.LineEvent",
-	.tp_basicsize = sizeof(gpiod_LineEventObject),
-	.tp_flags = Py_TPFLAGS_DEFAULT,
-	.tp_doc = gpiod_LineEventType_doc,
-	.tp_new = PyType_GenericNew,
-	.tp_init = (initproc)gpiod_LineEvent_init,
-	.tp_dealloc = (destructor)gpiod_LineEvent_dealloc,
-	.tp_getset = gpiod_LineEvent_getset,
-	.tp_repr = (reprfunc)gpiod_LineEvent_repr,
-};
-
-static int gpiod_Line_init(PyObject *Py_UNUSED(ignored0),
-			   PyObject *Py_UNUSED(ignored1),
-			   PyObject *Py_UNUSED(ignored2))
-{
-	PyErr_SetString(PyExc_NotImplementedError,
-			"Only gpiod.Chip can create new Line objects.");
-	return -1;
-}
-
-static void gpiod_Line_dealloc(gpiod_LineObject *self)
-{
-	if (self->owner)
-		Py_DECREF(self->owner);
-
-	PyObject_Del(self);
-}
-
-PyDoc_STRVAR(gpiod_Line_owner_doc,
-"owner() -> Chip object owning the line\n"
-"\n"
-"Get the GPIO chip owning this line.");
-
-static PyObject *gpiod_Line_owner(gpiod_LineObject *self,
-				  PyObject *Py_UNUSED(ignored))
-{
-	Py_INCREF(self->owner);
-	return (PyObject *)self->owner;
-}
-
-PyDoc_STRVAR(gpiod_Line_offset_doc,
-"offset() -> integer\n"
-"\n"
-"Get the offset of the GPIO line.");
-
-static PyObject *gpiod_Line_offset(gpiod_LineObject *self,
-				   PyObject *Py_UNUSED(ignored))
-{
-	if (gpiod_ChipIsClosed(self->owner))
-		return NULL;
-
-	return Py_BuildValue("I", gpiod_line_offset(self->line));
-}
-
-PyDoc_STRVAR(gpiod_Line_name_doc,
-"name() -> string\n"
-"\n"
-"Get the name of the GPIO line.");
-
-static PyObject *gpiod_Line_name(gpiod_LineObject *self,
-				 PyObject *Py_UNUSED(ignored))
-{
-	const char *name;
-
-	if (gpiod_ChipIsClosed(self->owner))
-		return NULL;
-
-	name = gpiod_line_name(self->line);
-	if (name)
-		return PyUnicode_FromFormat("%s", name);
-
-	Py_RETURN_NONE;
-}
-
-PyDoc_STRVAR(gpiod_Line_consumer_doc,
-"consumer() -> string\n"
-"\n"
-"Get the consumer string of the GPIO line.");
-
-static PyObject *gpiod_Line_consumer(gpiod_LineObject *self,
-				     PyObject *Py_UNUSED(ignored))
-{
-	const char *consumer;
-
-	if (gpiod_ChipIsClosed(self->owner))
-		return NULL;
-
-	consumer = gpiod_line_consumer(self->line);
-	if (consumer)
-		return PyUnicode_FromFormat("%s", consumer);
-
-	Py_RETURN_NONE;
-}
-
-PyDoc_STRVAR(gpiod_Line_direction_doc,
-"direction() -> integer\n"
-"\n"
-"Get the direction setting of this GPIO line.");
-
-static PyObject *gpiod_Line_direction(gpiod_LineObject *self,
-				      PyObject *Py_UNUSED(ignored))
-{
-	PyObject *ret;
-	int dir;
-
-	if (gpiod_ChipIsClosed(self->owner))
-		return NULL;
-
-	dir = gpiod_line_direction(self->line);
-
-	if (dir == GPIOD_LINE_DIRECTION_INPUT)
-		ret = Py_BuildValue("I", gpiod_DIRECTION_INPUT);
-	else
-		ret = Py_BuildValue("I", gpiod_DIRECTION_OUTPUT);
-
-	return ret;
-}
-
-PyDoc_STRVAR(gpiod_Line_is_active_low_doc,
-"is_active_low() -> boolean\n"
-"\n"
-"Check if this line's signal is inverted");
-
-static PyObject *gpiod_Line_is_active_low(gpiod_LineObject *self,
-					  PyObject *Py_UNUSED(ignored))
-{
-	if (gpiod_ChipIsClosed(self->owner))
-		return NULL;
-
-	if (gpiod_line_is_active_low(self->line))
-		Py_RETURN_TRUE;
-	Py_RETURN_FALSE;
-}
-
-PyDoc_STRVAR(gpiod_Line_bias_doc,
-"bias() -> integer\n"
-"\n"
-"Get the bias setting of this GPIO line.");
-
-static PyObject *gpiod_Line_bias(gpiod_LineObject *self,
-				 PyObject *Py_UNUSED(ignored))
-{
-	int bias;
-
-	if (gpiod_ChipIsClosed(self->owner))
-		return NULL;
-
-	bias = gpiod_line_bias(self->line);
-
-	switch (bias) {
-	case GPIOD_LINE_BIAS_PULL_UP:
-		return Py_BuildValue("I", gpiod_BIAS_PULL_UP);
-	case GPIOD_LINE_BIAS_PULL_DOWN:
-		return Py_BuildValue("I", gpiod_BIAS_PULL_DOWN);
-	case GPIOD_LINE_BIAS_DISABLED:
-		return Py_BuildValue("I", gpiod_BIAS_DISABLED);
-	case GPIOD_LINE_BIAS_UNKNOWN:
-	default:
-		return Py_BuildValue("I", gpiod_BIAS_UNKNOWN);
-	}
-}
-
-PyDoc_STRVAR(gpiod_Line_is_used_doc,
-"is_used() -> boolean\n"
-"\n"
-"Check if this line is used by the kernel or other user space process.");
-
-static PyObject *gpiod_Line_is_used(gpiod_LineObject *self,
-				    PyObject *Py_UNUSED(ignored))
-{
-	if (gpiod_ChipIsClosed(self->owner))
-		return NULL;
-
-	if (gpiod_line_is_used(self->line))
-		Py_RETURN_TRUE;
-
-	Py_RETURN_FALSE;
-}
-
-PyDoc_STRVAR(gpiod_Line_drive_doc,
-"drive() -> integer\n"
-"\n"
-"Get the current drive setting of this GPIO line.");
-
-static PyObject *gpiod_Line_drive(gpiod_LineObject *self,
-				  PyObject *Py_UNUSED(ignored))
-{
-	int drive;
-
-	if (gpiod_ChipIsClosed(self->owner))
-		return NULL;
-
-	drive = gpiod_line_drive(self->line);
-
-	switch (drive) {
-	case GPIOD_LINE_DRIVE_OPEN_DRAIN:
-		return Py_BuildValue("I", gpiod_DRIVE_OPEN_DRAIN);
-	case GPIOD_LINE_DRIVE_OPEN_SOURCE:
-		return Py_BuildValue("I", gpiod_DRIVE_OPEN_SOURCE);
-	case GPIOD_LINE_DRIVE_PUSH_PULL:
-	default:
-		return Py_BuildValue("I", gpiod_DRIVE_PUSH_PULL);
-	}
-}
-
-PyDoc_STRVAR(gpiod_Line_request_doc,
-"request(consumer[, type[, flags[, default_val]]]) -> None\n"
-"\n"
-"Request this GPIO line.\n"
-"\n"
-"  consumer\n"
-"    Name of the consumer.\n"
-"  type\n"
-"    Type of the request.\n"
-"  flags\n"
-"    Other configuration flags.\n"
-"  default_val\n"
-"    Default value of this line."
-"\n"
-"Note: default_vals argument (sequence of default values passed down to\n"
-"LineBulk.request()) is still supported for backward compatibility but is\n"
-"now deprecated when requesting single lines.");
-
-static PyObject *gpiod_Line_request(gpiod_LineObject *self,
-				    PyObject *args, PyObject *kwds)
-{
-	PyObject *ret, *def_val, *def_vals;
-	gpiod_LineBulkObject *bulk_obj;
-	int rv;
-
-	if (kwds && PyDict_Size(kwds) > 0) {
-		def_val = PyDict_GetItemString(kwds, "default_val");
-		def_vals = PyDict_GetItemString(kwds, "default_vals");
-	} else {
-		def_val = def_vals = NULL;
-	}
-
-	if (def_val && def_vals) {
-		PyErr_SetString(PyExc_TypeError,
-				"Cannot pass both default_val and default_vals arguments at the same time");
-		return NULL;
-	}
-
-	if (def_val) {
-		/*
-		 * If default_val was passed as a single value, we wrap it
-		 * in a tuple and add it to the kwds dictionary to be passed
-		 * down to LineBulk.request(). We also remove the 'default_val'
-		 * entry from kwds.
-		 *
-		 * I'm not sure if it's allowed to modify the kwds dictionary
-		 * but it doesn't seem to cause any problems. If it does then
-		 * we can simply copy the dictionary before calling
-		 * LineBulk.request().
-		 */
-		rv = PyDict_DelItemString(kwds, "default_val");
-		if (rv)
-			return NULL;
-
-		def_vals = Py_BuildValue("(O)", def_val);
-		if (!def_vals)
-			return NULL;
-
-		rv = PyDict_SetItemString(kwds, "default_vals", def_vals);
-		if (rv) {
-			Py_DECREF(def_vals);
-			return NULL;
-		}
-	}
-
-	bulk_obj = gpiod_LineToLineBulk(self);
-	if (!bulk_obj)
-		return NULL;
-
-	ret = gpiod_CallMethodPyArgs((PyObject *)bulk_obj,
-				     "request", args, kwds);
-	Py_DECREF(bulk_obj);
-
-	return ret;
-}
-
-PyDoc_STRVAR(gpiod_Line_get_value_doc,
-"get_value() -> integer\n"
-"\n"
-"Read the current value of this GPIO line.");
-
-static PyObject *gpiod_Line_get_value(gpiod_LineObject *self,
-				      PyObject *Py_UNUSED(ignored))
-{
-	gpiod_LineBulkObject *bulk_obj;
-	PyObject *vals, *ret;
-
-	bulk_obj = gpiod_LineToLineBulk(self);
-	if (!bulk_obj)
-		return NULL;
-
-	vals = PyObject_CallMethod((PyObject *)bulk_obj, "get_values", "");
-	Py_DECREF(bulk_obj);
-	if (!vals)
-		return NULL;
-
-	ret = PyList_GetItem(vals, 0);
-	Py_INCREF(ret);
-	Py_DECREF(vals);
-
-	return ret;
-}
-
-PyDoc_STRVAR(gpiod_Line_set_value_doc,
-"set_value(value) -> None\n"
-"\n"
-"Set the value of this GPIO line.\n"
-"\n"
-"  value\n"
-"    New value (integer)");
-
-static PyObject *gpiod_Line_set_value(gpiod_LineObject *self, PyObject *args)
-{
-	gpiod_LineBulkObject *bulk_obj;
-	PyObject *val, *vals, *ret;
-	int rv;
-
-	rv = PyArg_ParseTuple(args, "O", &val);
-	if (!rv)
-		return NULL;
-
-	bulk_obj = gpiod_LineToLineBulk(self);
-	if (!bulk_obj)
-		return NULL;
-
-	vals = Py_BuildValue("(O)", val);
-	if (!vals) {
-		Py_DECREF(bulk_obj);
-		return NULL;
-	}
-
-	ret = PyObject_CallMethod((PyObject *)bulk_obj,
-				  "set_values", "(O)", vals);
-	Py_DECREF(bulk_obj);
-	Py_DECREF(vals);
-
-	return ret;
-}
-
-PyDoc_STRVAR(gpiod_Line_set_config_doc,
-"set_config(direction,flags,value) -> None\n"
-"\n"
-"Set the configuration of this GPIO line.\n"
-"\n"
-"  direction\n"
-"    New direction (integer)\n"
-"  flags\n"
-"    New flags (integer)\n"
-"  value\n"
-"    New value (integer)");
-
-static PyObject *gpiod_Line_set_config(gpiod_LineObject *self, PyObject *args)
-{
-	gpiod_LineBulkObject *bulk_obj;
-	PyObject *dirn, *flags, *val, *vals, *ret;
-	int rv;
-
-	val = NULL;
-	rv = PyArg_ParseTuple(args, "OO|O", &dirn, &flags, &val);
-	if (!rv)
-		return NULL;
-
-	bulk_obj = gpiod_LineToLineBulk(self);
-	if (!bulk_obj)
-		return NULL;
-
-	if (val) {
-		vals = Py_BuildValue("(O)", val);
-		if (!vals) {
-			Py_DECREF(bulk_obj);
-			return NULL;
-		}
-		ret = PyObject_CallMethod((PyObject *)bulk_obj,
-				"set_config", "OO(O)", dirn, flags, vals);
-		Py_DECREF(vals);
-	} else {
-		ret = PyObject_CallMethod((PyObject *)bulk_obj,
-				"set_config", "OO", dirn, flags);
-	}
-
-	Py_DECREF(bulk_obj);
-
-	return ret;
-}
-
-PyDoc_STRVAR(gpiod_Line_set_flags_doc,
-"set_flags(flags) -> None\n"
-"\n"
-"Set the flags of this GPIO line.\n"
-"\n"
-"  flags\n"
-"    New flags (integer)");
-
-static PyObject *gpiod_Line_set_flags(gpiod_LineObject *self, PyObject *args)
-{
-	gpiod_LineBulkObject *bulk_obj;
-	PyObject *ret;
-
-	bulk_obj = gpiod_LineToLineBulk(self);
-	if (!bulk_obj)
-		return NULL;
-
-	ret = PyObject_CallMethod((PyObject *)bulk_obj,
-				  "set_flags", "O", args);
-	Py_DECREF(bulk_obj);
-
-	return ret;
-}
-
-PyDoc_STRVAR(gpiod_Line_set_direction_input_doc,
-"set_direction_input() -> None\n"
-"\n"
-"Set the direction of this GPIO line to input.\n");
-
-static PyObject *gpiod_Line_set_direction_input(gpiod_LineObject *self,
-						PyObject *Py_UNUSED(ignored))
-{
-	gpiod_LineBulkObject *bulk_obj;
-	PyObject *ret;
-
-	bulk_obj = gpiod_LineToLineBulk(self);
-	if (!bulk_obj)
-		return NULL;
-
-	ret = PyObject_CallMethod((PyObject *)bulk_obj,
-				  "set_direction_input", "");
-	Py_DECREF(bulk_obj);
-
-	return ret;
-}
-
-PyDoc_STRVAR(gpiod_Line_set_direction_output_doc,
-"set_direction_output(value) -> None\n"
-"\n"
-"Set the direction of this GPIO line to output.\n"
-"\n"
-"  value\n"
-"    New value (integer)");
-
-static PyObject *gpiod_Line_set_direction_output(gpiod_LineObject *self,
-						 PyObject *args)
-{
-	gpiod_LineBulkObject *bulk_obj;
-	PyObject *val, *vals, *ret;
-	int rv;
-	const char *fmt;
-
-	val = NULL;
-	rv = PyArg_ParseTuple(args, "|O", &val);
-	if (!rv)
-		return NULL;
-
-	if (val) {
-		fmt = "(O)";
-		vals = Py_BuildValue(fmt, val);
-	} else {
-		vals = Py_BuildValue("()");
-		fmt = "O"; /* pass empty args to bulk */
-	}
-	if (!vals)
-		return NULL;
-
-	bulk_obj = gpiod_LineToLineBulk(self);
-	if (!bulk_obj)
-		return NULL;
-
-	ret = PyObject_CallMethod((PyObject *)bulk_obj,
-				  "set_direction_output", fmt, vals);
-
-	Py_DECREF(bulk_obj);
-	Py_DECREF(vals);
-
-	return ret;
-}
-
-PyDoc_STRVAR(gpiod_Line_release_doc,
-"release() -> None\n"
-"\n"
-"Release this GPIO line.");
-
-static PyObject *gpiod_Line_release(gpiod_LineObject *self,
-				    PyObject *Py_UNUSED(ignored))
-{
-	gpiod_LineBulkObject *bulk_obj;
-	PyObject *ret;
-
-	bulk_obj = gpiod_LineToLineBulk(self);
-	if (!bulk_obj)
-		return NULL;
-
-	ret = PyObject_CallMethod((PyObject *)bulk_obj, "release", "");
-	Py_DECREF(bulk_obj);
-
-	return ret;
-}
-
-PyDoc_STRVAR(gpiod_Line_event_wait_doc,
-"event_wait([sec[ ,nsec]]) -> boolean\n"
-"\n"
-"Wait for a line event to occur on this GPIO line.\n"
-"\n"
-"  sec\n"
-"    Number of seconds to wait before timeout.\n"
-"  nsec\n"
-"    Number of nanoseconds to wait before timeout.\n"
-"\n"
-"Returns True if an event occurred on this line before timeout. False\n"
-"otherwise.");
-
-static PyObject *gpiod_Line_event_wait(gpiod_LineObject *self,
-				       PyObject *args, PyObject *kwds)
-{
-	gpiod_LineBulkObject *bulk_obj;
-	PyObject *events;
-
-	bulk_obj = gpiod_LineToLineBulk(self);
-	if (!bulk_obj)
-		return NULL;
-
-	events = gpiod_CallMethodPyArgs((PyObject *)bulk_obj,
-					"event_wait", args, kwds);
-	Py_DECREF(bulk_obj);
-	if (!events)
-		return NULL;
-
-	if (events == Py_None) {
-		Py_DECREF(Py_None);
-		Py_RETURN_FALSE;
-	}
-
-	Py_DECREF(events);
-	Py_RETURN_TRUE;
-}
-
-PyDoc_STRVAR(gpiod_Line_event_read_doc,
-"event_read() -> gpiod.LineEvent object\n"
-"\n"
-"Read a single line event from this GPIO line object.");
-
-static gpiod_LineEventObject *gpiod_Line_event_read(gpiod_LineObject *self,
-						    PyObject *Py_UNUSED(ignored))
-{
-	gpiod_LineEventObject *ret;
-	int rv;
-
-	if (gpiod_ChipIsClosed(self->owner))
-		return NULL;
-
-	ret = PyObject_New(gpiod_LineEventObject, &gpiod_LineEventType);
-	if (!ret)
-		return NULL;
-
-	ret->source = NULL;
-
-	Py_BEGIN_ALLOW_THREADS;
-	rv = gpiod_line_event_read(self->line, &ret->event);
-	Py_END_ALLOW_THREADS;
-	if (rv) {
-		Py_DECREF(ret);
-		return (gpiod_LineEventObject *)PyErr_SetFromErrno(
-							PyExc_OSError);
-	}
-
-	Py_INCREF(self);
-	ret->source = self;
-
-	return ret;
-}
-
-PyDoc_STRVAR(gpiod_Line_event_read_multiple_doc,
-"event_read_multiple() -> list of gpiod.LineEvent object\n"
-"\n"
-"Read multiple line events from this GPIO line object.");
-
-static PyObject *gpiod_Line_event_read_multiple(gpiod_LineObject *self,
-						PyObject *Py_UNUSED(ignored))
-{
-	struct gpiod_line_event evbuf[16];
-	gpiod_LineEventObject *event;
-	int rv, num_events, i;
-	PyObject *events;
-
-	if (gpiod_ChipIsClosed(self->owner))
-		return NULL;
-
-	memset(evbuf, 0, sizeof(evbuf));
-	Py_BEGIN_ALLOW_THREADS;
-	num_events = gpiod_line_event_read_multiple(self->line, evbuf,
-					sizeof(evbuf) / sizeof(*evbuf));
-	Py_END_ALLOW_THREADS;
-	if (num_events < 0)
-		return PyErr_SetFromErrno(PyExc_OSError);
-
-	events = PyList_New(num_events);
-	if (!events)
-		return NULL;
-
-	for (i = 0; i < num_events; i++) {
-		event = PyObject_New(gpiod_LineEventObject,
-				     &gpiod_LineEventType);
-		if (!event) {
-			Py_DECREF(events);
-			return NULL;
-		}
-
-		memcpy(&event->event, &evbuf[i], sizeof(event->event));
-		Py_INCREF(self);
-		event->source = self;
-
-		rv = PyList_SetItem(events, i, (PyObject *)event);
-		if (rv < 0) {
-			Py_DECREF(events);
-			Py_DECREF(event);
-			return NULL;
-		}
-	}
-
-	return events;
-}
-
-PyDoc_STRVAR(gpiod_Line_event_get_fd_doc,
-"event_get_fd() -> integer\n"
-"\n"
-"Get the event file descriptor number associated with this line.");
-
-static PyObject *gpiod_Line_event_get_fd(gpiod_LineObject *self,
-					 PyObject *Py_UNUSED(ignored))
-{
-	int fd;
-
-	if (gpiod_ChipIsClosed(self->owner))
-		return NULL;
-
-	fd = gpiod_line_event_get_fd(self->line);
-	if (fd < 0) {
-		PyErr_SetFromErrno(PyExc_OSError);
-		return NULL;
-	}
-
-	return PyLong_FromLong(fd);
-}
-
-static PyObject *gpiod_Line_repr(gpiod_LineObject *self)
-{
-	PyObject *chip_name, *ret;
-	const char *line_name;
-
-	if (gpiod_ChipIsClosed(self->owner))
-		return NULL;
-
-	chip_name = PyObject_CallMethod((PyObject *)self->owner, "name", "");
-	if (!chip_name)
-		return NULL;
-
-	line_name = gpiod_line_name(self->line);
-
-	ret = PyUnicode_FromFormat("'%S:%u /%s/'", chip_name,
-				   gpiod_line_offset(self->line),
-				   line_name ?: "unnamed");
-	Py_DECREF(chip_name);
-	return ret;
-}
-
-static PyMethodDef gpiod_Line_methods[] = {
-	{
-		.ml_name = "owner",
-		.ml_meth = (PyCFunction)gpiod_Line_owner,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_Line_owner_doc,
-	},
-	{
-		.ml_name = "offset",
-		.ml_meth = (PyCFunction)gpiod_Line_offset,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_Line_offset_doc,
-	},
-	{
-		.ml_name = "name",
-		.ml_meth = (PyCFunction)gpiod_Line_name,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_Line_name_doc,
-	},
-	{
-		.ml_name = "consumer",
-		.ml_meth = (PyCFunction)gpiod_Line_consumer,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_Line_consumer_doc,
-	},
-	{
-		.ml_name = "direction",
-		.ml_meth = (PyCFunction)gpiod_Line_direction,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_Line_direction_doc,
-	},
-	{
-		.ml_name = "is_active_low",
-		.ml_meth = (PyCFunction)gpiod_Line_is_active_low,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_Line_is_active_low_doc,
-	},
-	{
-		.ml_name = "bias",
-		.ml_meth = (PyCFunction)gpiod_Line_bias,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_Line_bias_doc,
-	},
-	{
-		.ml_name = "is_used",
-		.ml_meth = (PyCFunction)gpiod_Line_is_used,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_Line_is_used_doc,
-	},
-	{
-		.ml_name = "drive",
-		.ml_meth = (PyCFunction)gpiod_Line_drive,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_Line_drive_doc,
-	},
-	{
-		.ml_name = "request",
-		.ml_meth = (PyCFunction)(void (*)(void))gpiod_Line_request,
-		.ml_flags = METH_VARARGS | METH_KEYWORDS,
-		.ml_doc = gpiod_Line_request_doc,
-	},
-	{
-		.ml_name = "get_value",
-		.ml_meth = (PyCFunction)gpiod_Line_get_value,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_Line_get_value_doc,
-	},
-	{
-		.ml_name = "set_value",
-		.ml_meth = (PyCFunction)gpiod_Line_set_value,
-		.ml_flags = METH_VARARGS,
-		.ml_doc = gpiod_Line_set_value_doc,
-	},
-	{
-		.ml_name = "set_config",
-		.ml_meth = (PyCFunction)gpiod_Line_set_config,
-		.ml_flags = METH_VARARGS,
-		.ml_doc = gpiod_Line_set_config_doc,
-	},
-	{
-		.ml_name = "set_flags",
-		.ml_meth = (PyCFunction)gpiod_Line_set_flags,
-		.ml_flags = METH_VARARGS,
-		.ml_doc = gpiod_Line_set_flags_doc,
-	},
-	{
-		.ml_name = "set_direction_input",
-		.ml_meth = (PyCFunction)gpiod_Line_set_direction_input,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_Line_set_direction_input_doc,
-	},
-	{
-		.ml_name = "set_direction_output",
-		.ml_meth = (PyCFunction)gpiod_Line_set_direction_output,
-		.ml_flags = METH_VARARGS,
-		.ml_doc = gpiod_Line_set_direction_output_doc,
-	},
-	{
-		.ml_name = "release",
-		.ml_meth = (PyCFunction)gpiod_Line_release,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_Line_release_doc,
-	},
-	{
-		.ml_name = "event_wait",
-		.ml_meth = (PyCFunction)(void (*)(void))gpiod_Line_event_wait,
-		.ml_flags = METH_VARARGS | METH_KEYWORDS,
-		.ml_doc = gpiod_Line_event_wait_doc,
-	},
-	{
-		.ml_name = "event_read",
-		.ml_meth = (PyCFunction)gpiod_Line_event_read,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_Line_event_read_doc,
-	},
-	{
-		.ml_name = "event_read_multiple",
-		.ml_meth = (PyCFunction)gpiod_Line_event_read_multiple,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_Line_event_read_multiple_doc,
-	},
-	{
-		.ml_name = "event_get_fd",
-		.ml_meth = (PyCFunction)gpiod_Line_event_get_fd,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_Line_event_get_fd_doc,
-	},
-	{ }
-};
-
-PyDoc_STRVAR(gpiod_LineType_doc,
-"Represents a GPIO line.\n"
-"\n"
-"The lifetime of this object is managed by the chip that owns it. Once\n"
-"the corresponding gpiod.Chip is closed, a gpiod.Line object must not be\n"
-"used.\n"
-"\n"
-"Line objects can only be created by the owning chip.");
-
-static PyTypeObject gpiod_LineType = {
-	PyVarObject_HEAD_INIT(NULL, 0)
-	.tp_name = "gpiod.Line",
-	.tp_basicsize = sizeof(gpiod_LineObject),
-	.tp_flags = Py_TPFLAGS_DEFAULT,
-	.tp_doc = gpiod_LineType_doc,
-	.tp_new = PyType_GenericNew,
-	.tp_init = (initproc)gpiod_Line_init,
-	.tp_dealloc = (destructor)gpiod_Line_dealloc,
-	.tp_repr = (reprfunc)gpiod_Line_repr,
-	.tp_methods = gpiod_Line_methods,
-};
-
-static bool gpiod_LineBulkOwnerIsClosed(gpiod_LineBulkObject *self)
-{
-	gpiod_LineObject *line = (gpiod_LineObject *)self->lines[0];
-
-	return gpiod_ChipIsClosed(line->owner);
-}
-
-static int gpiod_LineBulk_init(gpiod_LineBulkObject *self,
-			       PyObject *args, PyObject *Py_UNUSED(ignored))
-{
-	PyObject *lines, *iter, *next;
-	Py_ssize_t i;
-	int rv;
-
-	rv = PyArg_ParseTuple(args, "O", &lines);
-	if (!rv)
-		return -1;
-
-	self->num_lines = PyObject_Size(lines);
-	if (self->num_lines < 1) {
-		PyErr_SetString(PyExc_TypeError,
-				"Argument must be a non-empty sequence");
-		return -1;
-	}
-	if (self->num_lines > LINE_REQUEST_MAX_LINES) {
-		PyErr_SetString(PyExc_TypeError,
-				"Too many objects in the sequence");
-		return -1;
-	}
-
-	self->lines = PyMem_Calloc(self->num_lines, sizeof(PyObject *));
-	if (!self->lines) {
-		PyErr_SetString(PyExc_MemoryError, "Out of memory");
-		return -1;
-	}
-
-	iter = PyObject_GetIter(lines);
-	if (!iter) {
-		PyMem_Free(self->lines);
-		return -1;
-	}
-
-	for (i = 0;;) {
-		next = PyIter_Next(iter);
-		if (!next) {
-			Py_DECREF(iter);
-			break;
-		}
-
-		if (next->ob_type != &gpiod_LineType) {
-			PyErr_SetString(PyExc_TypeError,
-					"Argument must be a sequence of GPIO lines");
-			Py_DECREF(next);
-			Py_DECREF(iter);
-			goto errout;
-		}
-
-		self->lines[i++] = next;
-	}
-
-	self->iter_idx = -1;
-
-	return 0;
-
-errout:
-
-	if (i > 0) {
-		for (--i; i >= 0; i--)
-			Py_DECREF(self->lines[i]);
-	}
-	PyMem_Free(self->lines);
-	self->lines = NULL;
-
-	return -1;
-}
-
-static void gpiod_LineBulk_dealloc(gpiod_LineBulkObject *self)
-{
-	Py_ssize_t i;
-
-	if (!self->lines)
-		return;
-
-	for (i = 0; i < self->num_lines; i++)
-		Py_DECREF(self->lines[i]);
-
-	PyMem_Free(self->lines);
-	PyObject_Del(self);
-}
-
-static PyObject *gpiod_LineBulk_iternext(gpiod_LineBulkObject *self)
-{
-	if (self->iter_idx < 0) {
-		self->iter_idx = 0; /* First element */
-	} else if (self->iter_idx >= self->num_lines) {
-		self->iter_idx = -1;
-		return NULL; /* Last element */
-	}
-
-	Py_INCREF(self->lines[self->iter_idx]);
-	return self->lines[self->iter_idx++];
-}
-
-PyDoc_STRVAR(gpiod_LineBulk_to_list_doc,
-"to_list() -> list of gpiod.Line objects\n"
-"\n"
-"Convert this LineBulk to a list");
-
-static PyObject *gpiod_LineBulk_to_list(gpiod_LineBulkObject *self,
-					PyObject *Py_UNUSED(ignored))
-{
-	PyObject *list;
-	Py_ssize_t i;
-	int rv;
-
-	list = PyList_New(self->num_lines);
-	if (!list)
-		return NULL;
-
-	for (i = 0; i < self->num_lines; i++) {
-		Py_INCREF(self->lines[i]);
-		rv = PyList_SetItem(list, i, self->lines[i]);
-		if (rv < 0) {
-			Py_DECREF(list);
-			return NULL;
-		}
-	}
-
-	return list;
-}
-
-static struct gpiod_line_bulk *
-gpiod_LineBulkObjToCLineBulk(gpiod_LineBulkObject *bulk_obj)
-{
-	struct gpiod_line_bulk *bulk;
-	gpiod_LineObject *line_obj;
-	Py_ssize_t i;
-
-	bulk = gpiod_line_bulk_new(bulk_obj->num_lines);
-	if (!bulk) {
-		PyErr_SetFromErrno(PyExc_OSError);
-		return NULL;
-	}
-
-	for (i = 0; i < bulk_obj->num_lines; i++) {
-		line_obj = (gpiod_LineObject *)bulk_obj->lines[i];
-		gpiod_line_bulk_add_line(bulk, line_obj->line);
-	}
-
-	return bulk;
-}
-
-static void gpiod_MakeRequestConfig(struct gpiod_line_request_config *conf,
-				    const char *consumer,
-				    int request_type, int flags)
-{
-	memset(conf, 0, sizeof(*conf));
-
-	conf->consumer = consumer;
-
-	switch (request_type) {
-	case gpiod_LINE_REQ_DIR_IN:
-		conf->request_type = GPIOD_LINE_REQUEST_DIRECTION_INPUT;
-		break;
-	case gpiod_LINE_REQ_DIR_OUT:
-		conf->request_type = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT;
-		break;
-	case gpiod_LINE_REQ_EV_FALLING_EDGE:
-		conf->request_type = GPIOD_LINE_REQUEST_EVENT_FALLING_EDGE;
-		break;
-	case gpiod_LINE_REQ_EV_RISING_EDGE:
-		conf->request_type = GPIOD_LINE_REQUEST_EVENT_RISING_EDGE;
-		break;
-	case gpiod_LINE_REQ_EV_BOTH_EDGES:
-		conf->request_type = GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES;
-		break;
-	case gpiod_LINE_REQ_DIR_AS_IS:
-	default:
-		conf->request_type = GPIOD_LINE_REQUEST_DIRECTION_AS_IS;
-		break;
-	}
-
-	if (flags & gpiod_LINE_REQ_FLAG_OPEN_DRAIN)
-		conf->flags |= GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN;
-	if (flags & gpiod_LINE_REQ_FLAG_OPEN_SOURCE)
-		conf->flags |= GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE;
-	if (flags & gpiod_LINE_REQ_FLAG_ACTIVE_LOW)
-		conf->flags |= GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
-	if (flags & gpiod_LINE_REQ_FLAG_BIAS_DISABLED)
-		conf->flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLED;
-	if (flags & gpiod_LINE_REQ_FLAG_BIAS_PULL_DOWN)
-		conf->flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN;
-	if (flags & gpiod_LINE_REQ_FLAG_BIAS_PULL_UP)
-		conf->flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP;
-}
-
-PyDoc_STRVAR(gpiod_LineBulk_request_doc,
-"request(consumer[, type[, flags[, default_vals]]]) -> None\n"
-"\n"
-"Request all lines held by this LineBulk object.\n"
-"\n"
-"  consumer\n"
-"    Name of the consumer.\n"
-"  type\n"
-"    Type of the request.\n"
-"  flags\n"
-"    Other configuration flags.\n"
-"  default_vals\n"
-"    List of default values.\n");
-
-static PyObject *gpiod_LineBulk_request(gpiod_LineBulkObject *self,
-					PyObject *args, PyObject *kwds)
-{
-	static char *kwlist[] = { "consumer",
-				  "type",
-				  "flags",
-				  "default_vals",
-				  NULL };
-
-	int rv, type = gpiod_LINE_REQ_DIR_AS_IS, flags = 0,
-	    vals[LINE_REQUEST_MAX_LINES], val;
-	PyObject *def_vals_obj = NULL, *iter, *next;
-	struct gpiod_line_request_config conf;
-	const int *default_vals = NULL;
-	struct gpiod_line_bulk *bulk;
-	Py_ssize_t num_def_vals;
-	char *consumer = NULL;
-	Py_ssize_t i;
-
-	if (gpiod_LineBulkOwnerIsClosed(self))
-		return NULL;
-
-	rv = PyArg_ParseTupleAndKeywords(args, kwds, "s|iiO", kwlist,
-					 &consumer, &type,
-					 &flags, &def_vals_obj);
-	if (!rv)
-		return NULL;
-
-	bulk = gpiod_LineBulkObjToCLineBulk(self);
-	if (!bulk)
-		return NULL;
-
-	gpiod_MakeRequestConfig(&conf, consumer, type, flags);
-
-	if (def_vals_obj) {
-		memset(vals, 0, sizeof(vals));
-
-		num_def_vals = PyObject_Size(def_vals_obj);
-		if (num_def_vals != self->num_lines) {
-			PyErr_SetString(PyExc_TypeError,
-					"Number of default values is not the same as the number of lines");
-			return NULL;
-		}
-
-		iter = PyObject_GetIter(def_vals_obj);
-		if (!iter)
-			return NULL;
-
-		for (i = 0;; i++) {
-			next = PyIter_Next(iter);
-			if (!next) {
-				Py_DECREF(iter);
-				break;
-			}
-
-			val = PyLong_AsUnsignedLong(next);
-			Py_DECREF(next);
-			if (PyErr_Occurred()) {
-				Py_DECREF(iter);
-				return NULL;
-			}
-
-			vals[i] = !!val;
-		}
-		default_vals = vals;
-	}
-
-	bulk = gpiod_LineBulkObjToCLineBulk(self);
-	if (!bulk)
-		return NULL;
-
-	Py_BEGIN_ALLOW_THREADS;
-	rv = gpiod_line_request_bulk(bulk, &conf, default_vals);
-	gpiod_line_bulk_free(bulk);
-	Py_END_ALLOW_THREADS;
-	if (rv)
-		return PyErr_SetFromErrno(PyExc_OSError);
-
-	Py_RETURN_NONE;
-}
-
-PyDoc_STRVAR(gpiod_LineBulk_get_values_doc,
-"get_values() -> list of integers\n"
-"\n"
-"Read the values of all the lines held by this LineBulk object. The index\n"
-"of each value in the returned list corresponds to the index of the line\n"
-"in this gpiod.LineBulk object.");
-
-static PyObject *gpiod_LineBulk_get_values(gpiod_LineBulkObject *self,
-					   PyObject *Py_UNUSED(ignored))
-{
-	int rv, vals[LINE_REQUEST_MAX_LINES];
-	struct gpiod_line_bulk *bulk;
-	PyObject *val_list, *val;
-	Py_ssize_t i;
-
-	if (gpiod_LineBulkOwnerIsClosed(self))
-		return NULL;
-
-	bulk = gpiod_LineBulkObjToCLineBulk(self);
-	if (!bulk)
-		return NULL;
-
-	memset(vals, 0, sizeof(vals));
-	Py_BEGIN_ALLOW_THREADS;
-	rv = gpiod_line_get_value_bulk(bulk, vals);
-	gpiod_line_bulk_free(bulk);
-	Py_END_ALLOW_THREADS;
-	if (rv)
-		return PyErr_SetFromErrno(PyExc_OSError);
-
-	val_list = PyList_New(self->num_lines);
-	if (!val_list)
-		return NULL;
-
-	for (i = 0; i < self->num_lines; i++) {
-		val = Py_BuildValue("i", vals[i]);
-		if (!val) {
-			Py_DECREF(val_list);
-			return NULL;
-		}
-
-		rv = PyList_SetItem(val_list, i, val);
-		if (rv < 0) {
-			Py_DECREF(val);
-			Py_DECREF(val_list);
-			return NULL;
-		}
-	}
-
-	return val_list;
-}
-
-static int gpiod_TupleToIntArray(PyObject *src, int *dst, Py_ssize_t nv)
-{
-	Py_ssize_t num_vals, i;
-	PyObject *iter, *next;
-	int val;
-
-	num_vals = PyObject_Size(src);
-	if (num_vals != nv) {
-		PyErr_SetString(PyExc_TypeError,
-				"Number of values must correspond to the number of lines");
-		return -1;
-	}
-
-	iter = PyObject_GetIter(src);
-	if (!iter)
-		return -1;
-
-	for (i = 0;; i++) {
-		next = PyIter_Next(iter);
-		if (!next) {
-			Py_DECREF(iter);
-			break;
-		}
-
-		val = PyLong_AsLong(next);
-		Py_DECREF(next);
-		if (PyErr_Occurred()) {
-			Py_DECREF(iter);
-			return -1;
-		}
-		dst[i] = (int)val;
-	}
-
-	return 0;
-}
-
-PyDoc_STRVAR(gpiod_LineBulk_set_values_doc,
-"set_values(values) -> None\n"
-"\n"
-"Set the values of all the lines held by this LineBulk object.\n"
-"\n"
-"  values\n"
-"    List of values (integers) to set.\n"
-"\n"
-"The number of values in the list passed as argument must be the same as\n"
-"the number of lines held by this gpiod.LineBulk object. The index of each\n"
-"value corresponds to the index of each line in the object.\n");
-
-static PyObject *gpiod_LineBulk_set_values(gpiod_LineBulkObject *self,
-					   PyObject *args)
-{
-	int rv, vals[LINE_REQUEST_MAX_LINES];
-	struct gpiod_line_bulk *bulk;
-	PyObject *val_list;
-
-	if (gpiod_LineBulkOwnerIsClosed(self))
-		return NULL;
-
-	memset(vals, 0, sizeof(vals));
-
-	rv = PyArg_ParseTuple(args, "O", &val_list);
-	if (!rv)
-		return NULL;
-
-	rv = gpiod_TupleToIntArray(val_list, vals, self->num_lines);
-	if (rv)
-		return NULL;
-
-	bulk = gpiod_LineBulkObjToCLineBulk(self);
-	if (!bulk)
-		return NULL;
-
-	Py_BEGIN_ALLOW_THREADS;
-	rv = gpiod_line_set_value_bulk(bulk, vals);
-	gpiod_line_bulk_free(bulk);
-	Py_END_ALLOW_THREADS;
-	if (rv)
-		return PyErr_SetFromErrno(PyExc_OSError);
-
-	Py_RETURN_NONE;
-}
-
-PyDoc_STRVAR(gpiod_LineBulk_set_config_doc,
-"set_config(direction,flags,values) -> None\n"
-"\n"
-"Set the configuration of all the lines held by this LineBulk object.\n"
-"\n"
-"  direction\n"
-"    New direction (integer)\n"
-"  flags\n"
-"    New flags (integer)\n"
-"  values\n"
-"    List of values (integers) to set when direction is output.\n"
-"\n"
-"The number of values in the list passed as argument must be the same as\n"
-"the number of lines held by this gpiod.LineBulk object. The index of each\n"
-"value corresponds to the index of each line in the object.\n");
-
-static PyObject *gpiod_LineBulk_set_config(gpiod_LineBulkObject *self,
-					   PyObject *args)
-{
-	int rv, vals[LINE_REQUEST_MAX_LINES];
-	struct gpiod_line_bulk *bulk;
-	PyObject *val_list;
-	const int *valp;
-	int dirn, flags;
-
-	if (gpiod_LineBulkOwnerIsClosed(self))
-		return NULL;
-
-	val_list = NULL;
-	rv = PyArg_ParseTuple(args, "ii|(O)", &dirn, &flags, &val_list);
-	if (!rv)
-		return NULL;
-
-	if (val_list == NULL) {
-		valp = NULL;
-	} else {
-		memset(vals, 0, sizeof(vals));
-		rv = gpiod_TupleToIntArray(val_list, vals, self->num_lines);
-		if (rv)
-			return NULL;
-		valp = vals;
-	}
-
-	bulk = gpiod_LineBulkObjToCLineBulk(self);
-	if (!bulk)
-		return NULL;
-
-	Py_BEGIN_ALLOW_THREADS;
-	rv = gpiod_line_set_config_bulk(bulk, dirn, flags, valp);
-	Py_END_ALLOW_THREADS;
-	if (rv)
-		return PyErr_SetFromErrno(PyExc_OSError);
-
-	Py_RETURN_NONE;
-}
-
-PyDoc_STRVAR(gpiod_LineBulk_set_flags_doc,
-"set_flags(flags) -> None\n"
-"\n"
-"Set the flags of all the lines held by this LineBulk object.\n"
-"\n"
-"  flags\n"
-"    New flags (integer)");
-
-static PyObject *gpiod_LineBulk_set_flags(gpiod_LineBulkObject *self,
-					  PyObject *args)
-{
-	struct gpiod_line_bulk *bulk;
-	int rv, flags;
-
-	if (gpiod_LineBulkOwnerIsClosed(self))
-		return NULL;
-
-	rv = PyArg_ParseTuple(args, "i", &flags);
-	if (!rv)
-		return NULL;
-
-	bulk = gpiod_LineBulkObjToCLineBulk(self);
-	if (!bulk)
-		return NULL;
-
-	Py_BEGIN_ALLOW_THREADS;
-	rv = gpiod_line_set_flags_bulk(bulk, flags);
-	gpiod_line_bulk_free(bulk);
-	Py_END_ALLOW_THREADS;
-	if (rv)
-		return PyErr_SetFromErrno(PyExc_OSError);
-
-	Py_RETURN_NONE;
-}
-
-PyDoc_STRVAR(gpiod_LineBulk_set_direction_input_doc,
-"set_direction_input() -> None\n"
-"\n"
-"Set the direction of all the lines held by this LineBulk object to input.\n");
-
-static PyObject *gpiod_LineBulk_set_direction_input(gpiod_LineBulkObject *self,
-						PyObject *Py_UNUSED(ignored))
-{
-	struct gpiod_line_bulk *bulk;
-	int rv;
-
-	if (gpiod_LineBulkOwnerIsClosed(self))
-		return NULL;
-
-	bulk = gpiod_LineBulkObjToCLineBulk(self);
-	if (!bulk)
-		return NULL;
-
-	Py_BEGIN_ALLOW_THREADS;
-	rv = gpiod_line_set_direction_input_bulk(bulk);
-	gpiod_line_bulk_free(bulk);
-	Py_END_ALLOW_THREADS;
-	if (rv)
-		return PyErr_SetFromErrno(PyExc_OSError);
-
-	Py_RETURN_NONE;
-}
-
-PyDoc_STRVAR(gpiod_LineBulk_set_direction_output_doc,
-"set_direction_output(value) -> None\n"
-"\n"
-"Set the direction of all the lines held by this LineBulk object to output.\n"
-"\n"
-"  values\n"
-"    List of values (integers) to set when direction is output.\n"
-"\n"
-"The number of values in the list passed as argument must be the same as\n"
-"the number of lines held by this gpiod.LineBulk object. The index of each\n"
-"value corresponds to the index of each line in the object.\n");
-
-static PyObject *gpiod_LineBulk_set_direction_output(
-				gpiod_LineBulkObject *self,
-				PyObject *args)
-{
-	int rv, vals[LINE_REQUEST_MAX_LINES];
-	struct gpiod_line_bulk *bulk;
-	PyObject *val_list;
-	const int *valp;
-
-	if (gpiod_LineBulkOwnerIsClosed(self))
-		return NULL;
-
-	val_list = NULL;
-	rv = PyArg_ParseTuple(args, "|O", &val_list);
-	if (!rv)
-		return NULL;
-
-	if (val_list == NULL)
-		valp = NULL;
-	else {
-		memset(vals, 0, sizeof(vals));
-		rv = gpiod_TupleToIntArray(val_list, vals, self->num_lines);
-		if (rv)
-			return NULL;
-		valp = vals;
-	}
-
-	bulk = gpiod_LineBulkObjToCLineBulk(self);
-	if (!bulk)
-		return NULL;
-
-	Py_BEGIN_ALLOW_THREADS;
-	rv = gpiod_line_set_direction_output_bulk(bulk, valp);
-	gpiod_line_bulk_free(bulk);
-	Py_END_ALLOW_THREADS;
-	if (rv)
-		return PyErr_SetFromErrno(PyExc_OSError);
-
-	Py_RETURN_NONE;
-}
-
-PyDoc_STRVAR(gpiod_LineBulk_release_doc,
-"release() -> None\n"
-"\n"
-"Release all lines held by this LineBulk object.");
-
-static PyObject *gpiod_LineBulk_release(gpiod_LineBulkObject *self,
-					PyObject *Py_UNUSED(ignored))
-{
-	struct gpiod_line_bulk *bulk;
-
-	if (gpiod_LineBulkOwnerIsClosed(self))
-		return NULL;
-
-	bulk = gpiod_LineBulkObjToCLineBulk(self);
-	if (!bulk)
-		return NULL;
-
-	gpiod_line_release_bulk(bulk);
-	gpiod_line_bulk_free(bulk);
-
-	Py_RETURN_NONE;
-}
-
-PyDoc_STRVAR(gpiod_LineBulk_event_wait_doc,
-"event_wait([sec[ ,nsec]]) -> gpiod.LineBulk object or None\n"
-"\n"
-"Poll the lines held by this LineBulk Object for line events.\n"
-"\n"
-"  sec\n"
-"    Number of seconds to wait before timeout.\n"
-"  nsec\n"
-"    Number of nanoseconds to wait before timeout.\n"
-"\n"
-"Returns a gpiod.LineBulk object containing references to lines on which\n"
-"events occurred or None if we reached the timeout without any event\n"
-"occurring.");
-
-static PyObject *gpiod_LineBulk_event_wait(gpiod_LineBulkObject *self,
-					   PyObject *args, PyObject *kwds)
-{
-	static char *kwlist[] = { "sec", "nsec", NULL };
-
-	struct gpiod_line_bulk *bulk, *ev_bulk;
-	gpiod_LineObject *line_obj;
-	gpiod_ChipObject *owner;
-	long sec = 0, nsec = 0;
-	struct timespec ts;
-	PyObject *ret;
-	unsigned int idx;
-	int rv;
-
-	if (gpiod_LineBulkOwnerIsClosed(self))
-		return NULL;
-
-	rv = PyArg_ParseTupleAndKeywords(args, kwds,
-					 "|ll", kwlist, &sec, &nsec);
-	if (!rv)
-		return NULL;
-
-	ts.tv_sec = sec;
-	ts.tv_nsec = nsec;
-
-	bulk = gpiod_LineBulkObjToCLineBulk(self);
-	if (!bulk)
-		return NULL;
-
-	ev_bulk = gpiod_line_bulk_new(self->num_lines);
-	if (!ev_bulk) {
-		gpiod_line_bulk_free(bulk);
-		return NULL;
-	}
-
-	Py_BEGIN_ALLOW_THREADS;
-	rv = gpiod_line_event_wait_bulk(bulk, &ts, ev_bulk);
-	gpiod_line_bulk_free(bulk);
-	Py_END_ALLOW_THREADS;
-	if (rv < 0) {
-		gpiod_line_bulk_free(ev_bulk);
-		return PyErr_SetFromErrno(PyExc_OSError);
-	} else if (rv == 0) {
-		gpiod_line_bulk_free(ev_bulk);
-		Py_RETURN_NONE;
-	}
-
-	ret = PyList_New(gpiod_line_bulk_num_lines(ev_bulk));
-	if (!ret) {
-		gpiod_line_bulk_free(ev_bulk);
-		return NULL;
-	}
-
-	owner = ((gpiod_LineObject *)(self->lines[0]))->owner;
-
-	for (idx = 0; idx < gpiod_line_bulk_num_lines(ev_bulk); idx++) {
-		line_obj = gpiod_MakeLineObject(owner, gpiod_line_bulk_get_line(ev_bulk, idx));
-		if (!line_obj) {
-			gpiod_line_bulk_free(ev_bulk);
-			Py_DECREF(ret);
-			return NULL;
-		}
-
-		rv = PyList_SetItem(ret, idx, (PyObject *)line_obj);
-		if (rv < 0) {
-			gpiod_line_bulk_free(ev_bulk);
-			Py_DECREF(ret);
-			return NULL;
-		}
-	}
-
-	gpiod_line_bulk_free(ev_bulk);
-
-	return ret;
-}
-
-static PyObject *gpiod_LineBulk_repr(gpiod_LineBulkObject *self)
-{
-	PyObject *list, *list_repr, *chip_name, *ret;
-	gpiod_LineObject *line;
-
-	if (gpiod_LineBulkOwnerIsClosed(self))
-		return NULL;
-
-	list = gpiod_LineBulk_to_list(self, NULL);
-	if (!list)
-		return NULL;
-
-	list_repr = PyObject_Repr(list);
-	Py_DECREF(list);
-	if (!list_repr)
-		return NULL;
-
-	line = (gpiod_LineObject *)self->lines[0];
-	chip_name = PyObject_CallMethod((PyObject *)line->owner, "name", "");
-	if (!chip_name) {
-		Py_DECREF(list_repr);
-		return NULL;
-	}
-
-	ret = PyUnicode_FromFormat("%U%U", chip_name, list_repr);
-	Py_DECREF(chip_name);
-	Py_DECREF(list_repr);
-	return ret;
-}
-
-static PyMethodDef gpiod_LineBulk_methods[] = {
-	{
-		.ml_name = "to_list",
-		.ml_meth = (PyCFunction)gpiod_LineBulk_to_list,
-		.ml_doc = gpiod_LineBulk_to_list_doc,
-		.ml_flags = METH_NOARGS,
-	},
-	{
-		.ml_name = "request",
-		.ml_meth = (PyCFunction)(void (*)(void))gpiod_LineBulk_request,
-		.ml_doc = gpiod_LineBulk_request_doc,
-		.ml_flags = METH_VARARGS | METH_KEYWORDS,
-	},
-	{
-		.ml_name = "get_values",
-		.ml_meth = (PyCFunction)gpiod_LineBulk_get_values,
-		.ml_doc = gpiod_LineBulk_get_values_doc,
-		.ml_flags = METH_NOARGS,
-	},
-	{
-		.ml_name = "set_values",
-		.ml_meth = (PyCFunction)gpiod_LineBulk_set_values,
-		.ml_doc = gpiod_LineBulk_set_values_doc,
-		.ml_flags = METH_VARARGS,
-	},
-	{
-		.ml_name = "set_config",
-		.ml_meth = (PyCFunction)gpiod_LineBulk_set_config,
-		.ml_flags = METH_VARARGS,
-		.ml_doc = gpiod_LineBulk_set_config_doc,
-	},
-	{
-		.ml_name = "set_flags",
-		.ml_meth = (PyCFunction)gpiod_LineBulk_set_flags,
-		.ml_flags = METH_VARARGS,
-		.ml_doc = gpiod_LineBulk_set_flags_doc,
-	},
-	{
-		.ml_name = "set_direction_input",
-		.ml_meth = (PyCFunction)gpiod_LineBulk_set_direction_input,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_LineBulk_set_direction_input_doc,
-	},
-	{
-		.ml_name = "set_direction_output",
-		.ml_meth = (PyCFunction)gpiod_LineBulk_set_direction_output,
-		.ml_flags = METH_VARARGS,
-		.ml_doc = gpiod_LineBulk_set_direction_output_doc,
-	},
-	{
-		.ml_name = "release",
-		.ml_meth = (PyCFunction)gpiod_LineBulk_release,
-		.ml_doc = gpiod_LineBulk_release_doc,
-		.ml_flags = METH_NOARGS,
-	},
-	{
-		.ml_name = "event_wait",
-		.ml_meth = (PyCFunction)(void (*)(void))gpiod_LineBulk_event_wait,
-		.ml_doc = gpiod_LineBulk_event_wait_doc,
-		.ml_flags = METH_VARARGS | METH_KEYWORDS,
-	},
-	{ }
-};
-
-PyDoc_STRVAR(gpiod_LineBulkType_doc,
-"Represents a set of GPIO lines.\n"
-"\n"
-"Objects of this type are immutable. The constructor takes as argument\n"
-"a sequence of gpiod.Line objects. It doesn't accept objects of any other\n"
-"type.");
-
-static PyTypeObject gpiod_LineBulkType = {
-	PyVarObject_HEAD_INIT(NULL, 0)
-	.tp_name = "gpiod.LineBulk",
-	.tp_basicsize = sizeof(gpiod_LineBulkObject),
-	.tp_flags = Py_TPFLAGS_DEFAULT,
-	.tp_doc = gpiod_LineBulkType_doc,
-	.tp_new = PyType_GenericNew,
-	.tp_init = (initproc)gpiod_LineBulk_init,
-	.tp_dealloc = (destructor)gpiod_LineBulk_dealloc,
-	.tp_iter = PyObject_SelfIter,
-	.tp_iternext = (iternextfunc)gpiod_LineBulk_iternext,
-	.tp_repr = (reprfunc)gpiod_LineBulk_repr,
-	.tp_methods = gpiod_LineBulk_methods,
-};
-
-static gpiod_LineBulkObject *gpiod_LineToLineBulk(gpiod_LineObject *line)
-{
-	gpiod_LineBulkObject *ret;
-	PyObject *args;
-
-	args = Py_BuildValue("((O))", line);
-	if (!args)
-		return NULL;
-
-	ret = (gpiod_LineBulkObject *)PyObject_CallObject(
-					(PyObject *)&gpiod_LineBulkType,
-					args);
-	Py_DECREF(args);
-
-	return ret;
-}
-
-static int gpiod_Chip_init(gpiod_ChipObject *self,
-			   PyObject *args, PyObject *Py_UNUSED(ignored))
-{
-	char *path;
-	int rv;
-
-	rv = PyArg_ParseTuple(args, "s", &path);
-	if (!rv)
-		return -1;
-
-	Py_BEGIN_ALLOW_THREADS;
-	self->chip = gpiod_chip_open(path);
-	Py_END_ALLOW_THREADS;
-	if (!self->chip) {
-		PyErr_SetFromErrno(PyExc_OSError);
-		return -1;
-	}
-
-	return 0;
-}
-
-static void gpiod_Chip_dealloc(gpiod_ChipObject *self)
-{
-	if (self->chip)
-		gpiod_chip_unref(self->chip);
-
-	PyObject_Del(self);
-}
-
-static PyObject *gpiod_Chip_repr(gpiod_ChipObject *self)
-{
-	if (gpiod_ChipIsClosed(self))
-		return NULL;
-
-	return PyUnicode_FromFormat("'%s /%s/ %u lines'",
-				    gpiod_chip_get_name(self->chip),
-				    gpiod_chip_get_label(self->chip),
-				    gpiod_chip_get_num_lines(self->chip));
-}
-
-PyDoc_STRVAR(gpiod_Chip_close_doc,
-"close() -> None\n"
-"\n"
-"Close the associated gpiochip descriptor. The chip object must no longer\n"
-"be used after this method is called.\n");
-
-static PyObject *gpiod_Chip_close(gpiod_ChipObject *self,
-				  PyObject *Py_UNUSED(ignored))
-{
-	if (gpiod_ChipIsClosed(self))
-		return NULL;
-
-	gpiod_chip_unref(self->chip);
-	self->chip = NULL;
-
-	Py_RETURN_NONE;
-}
-
-PyDoc_STRVAR(gpiod_Chip_enter_doc,
-"Controlled execution enter callback.");
-
-static PyObject *gpiod_Chip_enter(gpiod_ChipObject *chip,
-				  PyObject *Py_UNUSED(ignored))
-{
-	Py_INCREF(chip);
-	return (PyObject *)chip;
-}
-
-PyDoc_STRVAR(gpiod_Chip_exit_doc,
-"Controlled execution exit callback.");
-
-static PyObject *gpiod_Chip_exit(gpiod_ChipObject *chip,
-				 PyObject *Py_UNUSED(ignored))
-{
-	return PyObject_CallMethod((PyObject *)chip, "close", "");
-}
-
-PyDoc_STRVAR(gpiod_Chip_name_doc,
-"name() -> string\n"
-"\n"
-"Get the name of the GPIO chip");
-
-static PyObject *gpiod_Chip_name(gpiod_ChipObject *self,
-				 PyObject *Py_UNUSED(ignored))
-{
-	if (gpiod_ChipIsClosed(self))
-		return NULL;
-
-	return PyUnicode_FromFormat("%s", gpiod_chip_get_name(self->chip));
-}
-
-PyDoc_STRVAR(gpiod_Chip_label_doc,
-"label() -> string\n"
-"\n"
-"Get the label of the GPIO chip");
-
-static PyObject *gpiod_Chip_label(gpiod_ChipObject *self,
-				  PyObject *Py_UNUSED(ignored))
-{
-	if (gpiod_ChipIsClosed(self))
-		return NULL;
-
-	return PyUnicode_FromFormat("%s", gpiod_chip_get_label(self->chip));
-}
-
-PyDoc_STRVAR(gpiod_Chip_num_lines_doc,
-"num_lines() -> integer\n"
-"\n"
-"Get the number of lines exposed by this GPIO chip.");
-
-static PyObject *gpiod_Chip_num_lines(gpiod_ChipObject *self,
-				      PyObject *Py_UNUSED(ignored))
-{
-	if (gpiod_ChipIsClosed(self))
-		return NULL;
-
-	return Py_BuildValue("I", gpiod_chip_get_num_lines(self->chip));
-}
-
-static gpiod_LineObject *
-gpiod_MakeLineObject(gpiod_ChipObject *owner, struct gpiod_line *line)
-{
-	gpiod_LineObject *obj;
-
-	obj = PyObject_New(gpiod_LineObject, &gpiod_LineType);
-	if (!obj)
-		return NULL;
-
-	obj->line = line;
-	Py_INCREF(owner);
-	obj->owner = owner;
-
-	return obj;
-}
-
-PyDoc_STRVAR(gpiod_Chip_get_line_doc,
-"get_line(offset) -> gpiod.Line object\n"
-"\n"
-"Get the GPIO line at given offset.\n"
-"\n"
-"  offset\n"
-"    Line offset (integer)");
-
-static gpiod_LineObject *
-gpiod_Chip_get_line(gpiod_ChipObject *self, PyObject *args)
-{
-	struct gpiod_line *line;
-	unsigned int offset;
-	int rv;
-
-	if (gpiod_ChipIsClosed(self))
-		return NULL;
-
-	rv = PyArg_ParseTuple(args, "I", &offset);
-	if (!rv)
-		return NULL;
-
-	Py_BEGIN_ALLOW_THREADS;
-	line = gpiod_chip_get_line(self->chip, offset);
-	Py_END_ALLOW_THREADS;
-	if (!line)
-		return (gpiod_LineObject *)PyErr_SetFromErrno(PyExc_OSError);
-
-	return gpiod_MakeLineObject(self, line);
-}
-
-static gpiod_LineBulkObject *gpiod_ListToLineBulk(PyObject *lines)
-{
-	gpiod_LineBulkObject *bulk;
-	PyObject *arg;
-
-	arg = PyTuple_Pack(1, lines);
-	if (!arg)
-		return NULL;
-
-	bulk = (gpiod_LineBulkObject *)PyObject_CallObject(
-					(PyObject *)&gpiod_LineBulkType,
-					arg);
-	Py_DECREF(arg);
-
-	return bulk;
-}
-
-static gpiod_LineBulkObject *
-gpiod_LineBulkObjectFromBulk(gpiod_ChipObject *chip, struct gpiod_line_bulk *bulk)
-{
-	gpiod_LineBulkObject *bulk_obj;
-	gpiod_LineObject *line_obj;
-	struct gpiod_line *line;
-	unsigned int idx;
-	PyObject *list;
-	int rv;
-
-	list = PyList_New(gpiod_line_bulk_num_lines(bulk));
-	if (!list)
-		return NULL;
-
-	for (idx = 0; idx < gpiod_line_bulk_num_lines(bulk); idx++) {
-		line = gpiod_line_bulk_get_line(bulk, idx);
-		line_obj = gpiod_MakeLineObject(chip, line);
-		if (!line_obj) {
-			Py_DECREF(list);
-			return NULL;
-		}
-
-		rv = PyList_SetItem(list, idx, (PyObject *)line_obj);
-		if (rv < 0) {
-			Py_DECREF(line_obj);
-			Py_DECREF(list);
-			return NULL;
-		}
-	}
-
-	bulk_obj = gpiod_ListToLineBulk(list);
-	Py_DECREF(list);
-	if (!bulk_obj)
-		return NULL;
-
-	return bulk_obj;
-}
-
-PyDoc_STRVAR(gpiod_Chip_find_line_doc,
-"find_line(name) -> integer or None\n"
-"\n"
-"Find the offset of the line with given name among lines exposed by this\n"
-"GPIO chip.\n"
-"\n"
-"  name\n"
-"    Line name (string)\n"
-"\n"
-"Returns the offset of the line with given name or None if it is not\n"
-"associated with this chip.");
-
-static PyObject *gpiod_Chip_find_line(gpiod_ChipObject *self, PyObject *args)
-{
-	const char *name;
-	int rv, offset;
-
-	if (gpiod_ChipIsClosed(self))
-		return NULL;
-
-	rv = PyArg_ParseTuple(args, "s", &name);
-	if (!rv)
-		return NULL;
-
-	Py_BEGIN_ALLOW_THREADS;
-	offset = gpiod_chip_find_line(self->chip, name);
-	Py_END_ALLOW_THREADS;
-	if (offset < 0) {
-		if (errno == ENOENT)
-			Py_RETURN_NONE;
-
-		return PyErr_SetFromErrno(PyExc_OSError);
-	}
-
-	return Py_BuildValue("i", offset);
-}
-
-PyDoc_STRVAR(gpiod_Chip_get_lines_doc,
-"get_lines(offsets) -> gpiod.LineBulk object\n"
-"\n"
-"Get a set of GPIO lines by their offsets.\n"
-"\n"
-"  offsets\n"
-"    List of lines offsets.");
-
-static gpiod_LineBulkObject *
-gpiod_Chip_get_lines(gpiod_ChipObject *self, PyObject *args)
-{
-	PyObject *offsets, *iter, *next, *lines, *arg;
-	gpiod_LineBulkObject *bulk;
-	Py_ssize_t num_offsets, i;
-	gpiod_LineObject *line;
-	int rv;
-
-	rv = PyArg_ParseTuple(args, "O", &offsets);
-	if (!rv)
-		return NULL;
-
-	num_offsets = PyObject_Size(offsets);
-	if (num_offsets < 1) {
-		PyErr_SetString(PyExc_TypeError,
-				"Argument must be a non-empty sequence of offsets");
-		return NULL;
-	}
-
-	lines = PyList_New(num_offsets);
-	if (!lines)
-		return NULL;
-
-	iter = PyObject_GetIter(offsets);
-	if (!iter) {
-		Py_DECREF(lines);
-		return NULL;
-	}
-
-	for (i = 0;;) {
-		next = PyIter_Next(iter);
-		if (!next) {
-			Py_DECREF(iter);
-			break;
-		}
-
-		arg = PyTuple_Pack(1, next);
-		Py_DECREF(next);
-		if (!arg) {
-			Py_DECREF(iter);
-			Py_DECREF(lines);
-			return NULL;
-		}
-
-		line = gpiod_Chip_get_line(self, arg);
-		Py_DECREF(arg);
-		if (!line) {
-			Py_DECREF(iter);
-			Py_DECREF(lines);
-			return NULL;
-		}
-
-		rv = PyList_SetItem(lines, i++, (PyObject *)line);
-		if (rv < 0) {
-			Py_DECREF(line);
-			Py_DECREF(iter);
-			Py_DECREF(lines);
-			return NULL;
-		}
-	}
-
-	bulk = gpiod_ListToLineBulk(lines);
-	Py_DECREF(lines);
-	if (!bulk)
-		return NULL;
-
-	return bulk;
-}
-
-PyDoc_STRVAR(gpiod_Chip_get_all_lines_doc,
-"get_all_lines() -> gpiod.LineBulk object\n"
-"\n"
-"Get all lines exposed by this Chip.");
-
-static gpiod_LineBulkObject *
-gpiod_Chip_get_all_lines(gpiod_ChipObject *self, PyObject *Py_UNUSED(ignored))
-{
-	gpiod_LineBulkObject *bulk_obj;
-	struct gpiod_line_bulk *bulk;
-
-	if (gpiod_ChipIsClosed(self))
-		return NULL;
-
-	bulk = gpiod_chip_get_all_lines(self->chip);
-	if (!bulk)
-		return (gpiod_LineBulkObject *)PyErr_SetFromErrno(
-							PyExc_OSError);
-
-	bulk_obj = gpiod_LineBulkObjectFromBulk(self, bulk);
-	gpiod_line_bulk_free(bulk);
-	return bulk_obj;
-}
-
-static PyMethodDef gpiod_Chip_methods[] = {
-	{
-		.ml_name = "close",
-		.ml_meth = (PyCFunction)gpiod_Chip_close,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_Chip_close_doc,
-	},
-	{
-		.ml_name = "__enter__",
-		.ml_meth = (PyCFunction)gpiod_Chip_enter,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_Chip_enter_doc,
-	},
-	{
-		.ml_name = "__exit__",
-		.ml_meth = (PyCFunction)gpiod_Chip_exit,
-		.ml_flags = METH_VARARGS,
-		.ml_doc = gpiod_Chip_exit_doc,
-	},
-	{
-		.ml_name = "name",
-		.ml_meth = (PyCFunction)gpiod_Chip_name,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_Chip_name_doc,
-	},
-	{
-		.ml_name = "label",
-		.ml_meth = (PyCFunction)gpiod_Chip_label,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_Chip_label_doc,
-	},
-	{
-		.ml_name = "num_lines",
-		.ml_meth = (PyCFunction)gpiod_Chip_num_lines,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_Chip_num_lines_doc,
-	},
-	{
-		.ml_name = "get_line",
-		.ml_meth = (PyCFunction)gpiod_Chip_get_line,
-		.ml_flags = METH_VARARGS,
-		.ml_doc = gpiod_Chip_get_line_doc,
-	},
-	{
-		.ml_name = "find_line",
-		.ml_meth = (PyCFunction)gpiod_Chip_find_line,
-		.ml_flags = METH_VARARGS,
-		.ml_doc = gpiod_Chip_find_line_doc,
-	},
-	{
-		.ml_name = "get_lines",
-		.ml_meth = (PyCFunction)gpiod_Chip_get_lines,
-		.ml_flags = METH_VARARGS,
-		.ml_doc = gpiod_Chip_get_lines_doc,
-	},
-	{
-		.ml_name = "get_all_lines",
-		.ml_meth = (PyCFunction)gpiod_Chip_get_all_lines,
-		.ml_flags = METH_NOARGS,
-		.ml_doc = gpiod_Chip_get_all_lines_doc,
-	},
-	{ }
-};
-
-PyDoc_STRVAR(gpiod_ChipType_doc,
-"Represents a GPIO chip.\n"
-"\n"
-"Chip object manages all resources associated with the GPIO chip\n"
-"it represents.\n"
-"\n"
-"The gpiochip device file is opened during the object's construction.\n"
-"The Chip object's constructor takes a description string as argument the\n"
-"meaning of which depends on the second, optional parameter which defines\n"
-"the way the description string should be interpreted. The available\n"
-"options are: OPEN_BY_NAME, OPEN_BY_NUMBER, OPEN_BY_PATH and OPEN_LOOKUP.\n"
-"The last option means that libgpiod should open the chip based on the best\n"
-"guess what the path is. This is also the default if the second argument is\n"
-"missing.\n"
-"\n"
-"Callers must close the chip by calling the close() method when it's no\n"
-"longer used.\n"
-"\n"
-"Example:\n"
-"\n"
-"    chip = gpiod.Chip('gpiochip0', gpiod.Chip.OPEN_BY_NAME)\n"
-"    do_something(chip)\n"
-"    chip.close()\n"
-"\n"
-"The gpiod.Chip class also supports controlled execution ('with' statement).\n"
-"\n"
-"Example:\n"
-"\n"
-"    with gpiod.Chip('0', gpiod.Chip.OPEN_BY_NUMBER) as chip:\n"
-"        do_something(chip)");
-
-static PyTypeObject gpiod_ChipType = {
-	PyVarObject_HEAD_INIT(NULL, 0)
-	.tp_name = "gpiod.Chip",
-	.tp_basicsize = sizeof(gpiod_ChipObject),
-	.tp_flags = Py_TPFLAGS_DEFAULT,
-	.tp_doc = gpiod_ChipType_doc,
-	.tp_new = PyType_GenericNew,
-	.tp_init = (initproc)gpiod_Chip_init,
-	.tp_dealloc = (destructor)gpiod_Chip_dealloc,
-	.tp_repr = (reprfunc)gpiod_Chip_repr,
-	.tp_methods = gpiod_Chip_methods,
-};
-
-static int gpiod_LineIter_init(gpiod_LineIterObject *self,
-			       PyObject *args, PyObject *Py_UNUSED(ignored))
-{
-	gpiod_ChipObject *chip_obj;
-	int rv;
-
-	rv = PyArg_ParseTuple(args, "O!", &gpiod_ChipType,
-			      (PyObject *)&chip_obj);
-	if (!rv)
-		return -1;
-
-	if (gpiod_ChipIsClosed(chip_obj))
-		return -1;
-
-	self->offset = 0;
-	self->owner = chip_obj;
-	Py_INCREF(chip_obj);
-
-	return 0;
-}
-
-static void gpiod_LineIter_dealloc(gpiod_LineIterObject *self)
-{
-	PyObject_Del(self);
-}
-
-static gpiod_LineObject *gpiod_LineIter_next(gpiod_LineIterObject *self)
-{
-	struct gpiod_line *line;
-
-	if (self->offset == gpiod_chip_get_num_lines(self->owner->chip))
-		return NULL; /* Last element. */
-
-	line = gpiod_chip_get_line(self->owner->chip, self->offset++);
-	if (!line)
-		return (gpiod_LineObject *)PyErr_SetFromErrno(PyExc_OSError);
-
-	return gpiod_MakeLineObject(self->owner, line);
-}
-
-PyDoc_STRVAR(gpiod_LineIterType_doc,
-"Allows to iterate over all lines exposed by a GPIO chip.\n"
-"\n"
-"New line iterator is created by passing a reference to an open gpiod.Chip\n"
-"object to the constructor of gpiod.LineIter.\n"
-"\n"
-"Caller doesn't need to handle the resource management for lines as their\n"
-"lifetime is managed by the owning chip.\n"
-"\n"
-"Example:\n"
-"\n"
-"    chip = gpiod.Chip('gpiochip0')\n"
-"    for line in gpiod.LineIter(chip):\n"
-"        do_stuff_with_line(line)");
-
-static PyTypeObject gpiod_LineIterType = {
-	PyVarObject_HEAD_INIT(NULL, 0)
-	.tp_name = "gpiod.LineIter",
-	.tp_basicsize = sizeof(gpiod_LineIterObject),
-	.tp_flags = Py_TPFLAGS_DEFAULT,
-	.tp_doc = gpiod_LineIterType_doc,
-	.tp_new = PyType_GenericNew,
-	.tp_init = (initproc)gpiod_LineIter_init,
-	.tp_dealloc = (destructor)gpiod_LineIter_dealloc,
-	.tp_iter = PyObject_SelfIter,
-	.tp_iternext = (iternextfunc)gpiod_LineIter_next,
-};
-
-typedef struct {
-	const char *name;
-	PyTypeObject *typeobj;
-} gpiod_PyType;
-
-static gpiod_PyType gpiod_PyType_list[] = {
-	{ .name = "Chip",	.typeobj = &gpiod_ChipType,		},
-	{ .name = "Line",	.typeobj = &gpiod_LineType,		},
-	{ .name = "LineEvent",	.typeobj = &gpiod_LineEventType,	},
-	{ .name = "LineBulk",	.typeobj = &gpiod_LineBulkType,		},
-	{ .name = "LineIter",	.typeobj = &gpiod_LineIterType,		},
-	{ }
-};
-
-typedef struct {
-	PyTypeObject *typeobj;
-	const char *name;
-	long int val;
-} gpiod_ConstDescr;
-
-static gpiod_ConstDescr gpiod_ConstList[] = {
-	{
-		.typeobj = &gpiod_LineType,
-		.name = "DIRECTION_INPUT",
-		.val = gpiod_DIRECTION_INPUT,
-	},
-	{
-		.typeobj = &gpiod_LineType,
-		.name = "DIRECTION_OUTPUT",
-		.val = gpiod_DIRECTION_OUTPUT,
-	},
-	{
-		.typeobj = &gpiod_LineType,
-		.name = "DRIVE_PUSH_PULL",
-		.val = gpiod_DRIVE_PUSH_PULL,
-	},
-	{
-		.typeobj = &gpiod_LineType,
-		.name = "DRIVE_OPEN_DRAIN",
-		.val = gpiod_DRIVE_OPEN_DRAIN,
-	},
-	{
-		.typeobj = &gpiod_LineType,
-		.name = "DRIVE_OPEN_SOURCE",
-		.val = gpiod_DRIVE_OPEN_SOURCE,
-	},
-	{
-		.typeobj = &gpiod_LineType,
-		.name = "BIAS_UNKNOWN",
-		.val = gpiod_BIAS_UNKNOWN,
-	},
-	{
-		.typeobj = &gpiod_LineType,
-		.name = "BIAS_DISABLED",
-		.val = gpiod_BIAS_DISABLED,
-	},
-	{
-		.typeobj = &gpiod_LineType,
-		.name = "BIAS_PULL_UP",
-		.val = gpiod_BIAS_PULL_UP,
-	},
-	{
-		.typeobj = &gpiod_LineType,
-		.name = "BIAS_PULL_DOWN",
-		.val = gpiod_BIAS_PULL_DOWN,
-	},
-	{
-		.typeobj = &gpiod_LineEventType,
-		.name = "RISING_EDGE",
-		.val = gpiod_RISING_EDGE,
-	},
-	{
-		.typeobj = &gpiod_LineEventType,
-		.name = "FALLING_EDGE",
-		.val = gpiod_FALLING_EDGE,
-	},
-	{ }
-};
-
-PyDoc_STRVAR(gpiod_Module_is_gpiochip_device_doc,
-"is_gpiochip_device(path) -> boolean\n"
-"\n"
-"Check if the file pointed to by path is a GPIO chip character device.\n"
-"Returns true if so, False otherwise.\n"
-"\n"
-"  path\n"
-"    Path to the file that should be checked.\n");
-
-static PyObject *
-gpiod_Module_is_gpiochip_device(PyObject *Py_UNUSED(self), PyObject *args)
-{
-	const char *path;
-	int ret;
-
-	ret = PyArg_ParseTuple(args, "s", &path);
-	if (!ret)
-		return NULL;
-
-	if (gpiod_is_gpiochip_device(path))
-		Py_RETURN_TRUE;
-
-	Py_RETURN_FALSE;
-}
-
-static PyMethodDef gpiod_module_methods[] = {
-	{
-		.ml_name = "is_gpiochip_device",
-		.ml_meth = (PyCFunction)gpiod_Module_is_gpiochip_device,
-		.ml_flags = METH_VARARGS,
-		.ml_doc = gpiod_Module_is_gpiochip_device_doc,
-	},
-	{ }
-};
-
-PyDoc_STRVAR(gpiod_Module_doc,
-"Python bindings for libgpiod.\n\
-\n\
-This module wraps the native C API of libgpiod in a set of python classes.");
-
-static PyModuleDef gpiod_Module = {
-	PyModuleDef_HEAD_INIT,
-	.m_name = "gpiod",
-	.m_doc = gpiod_Module_doc,
-	.m_size = -1,
-	.m_methods = gpiod_module_methods,
-};
-
-typedef struct {
-	const char *name;
-	long int value;
-} gpiod_ModuleConst;
-
-static gpiod_ModuleConst gpiod_ModuleConsts[] = {
-	{
-		.name = "LINE_REQ_DIR_AS_IS",
-		.value = gpiod_LINE_REQ_DIR_AS_IS,
-	},
-	{
-		.name = "LINE_REQ_DIR_IN",
-		.value = gpiod_LINE_REQ_DIR_IN,
-	},
-	{
-		.name = "LINE_REQ_DIR_OUT",
-		.value = gpiod_LINE_REQ_DIR_OUT,
-	},
-	{
-		.name = "LINE_REQ_EV_FALLING_EDGE",
-		.value = gpiod_LINE_REQ_EV_FALLING_EDGE,
-	},
-	{
-		.name = "LINE_REQ_EV_RISING_EDGE",
-		.value = gpiod_LINE_REQ_EV_RISING_EDGE,
-	},
-	{
-		.name = "LINE_REQ_EV_BOTH_EDGES",
-		.value = gpiod_LINE_REQ_EV_BOTH_EDGES,
-	},
-	{
-		.name = "LINE_REQ_FLAG_OPEN_DRAIN",
-		.value = gpiod_LINE_REQ_FLAG_OPEN_DRAIN,
-	},
-	{
-		.name = "LINE_REQ_FLAG_OPEN_SOURCE",
-		.value = gpiod_LINE_REQ_FLAG_OPEN_SOURCE,
-	},
-	{
-		.name = "LINE_REQ_FLAG_ACTIVE_LOW",
-		.value = gpiod_LINE_REQ_FLAG_ACTIVE_LOW,
-	},
-	{
-		.name = "LINE_REQ_FLAG_BIAS_DISABLED",
-		.value = gpiod_LINE_REQ_FLAG_BIAS_DISABLED,
-	},
-	{
-		.name = "LINE_REQ_FLAG_BIAS_PULL_DOWN",
-		.value = gpiod_LINE_REQ_FLAG_BIAS_PULL_DOWN,
-	},
-	{
-		.name = "LINE_REQ_FLAG_BIAS_PULL_UP",
-		.value = gpiod_LINE_REQ_FLAG_BIAS_PULL_UP,
-	},
-	{ }
-};
-
-PyMODINIT_FUNC PyInit_gpiod(void)
-{
-	gpiod_ConstDescr *const_descr;
-	gpiod_ModuleConst *mod_const;
-	PyObject *module, *val;
-	gpiod_PyType *type;
-	unsigned int i;
-	int rv;
-
-	module = PyModule_Create(&gpiod_Module);
-	if (!module)
-		return NULL;
-
-	for (i = 0; gpiod_PyType_list[i].typeobj; i++) {
-		type = &gpiod_PyType_list[i];
-
-		rv = PyType_Ready(type->typeobj);
-		if (rv)
-			return NULL;
-
-		Py_INCREF(type->typeobj);
-		rv = PyModule_AddObject(module, type->name,
-					(PyObject *)type->typeobj);
-		if (rv < 0)
-			return NULL;
-	}
-
-	for (i = 0; gpiod_ConstList[i].name; i++) {
-		const_descr = &gpiod_ConstList[i];
-
-		val = PyLong_FromLong(const_descr->val);
-		if (!val)
-			return NULL;
-
-		rv = PyDict_SetItemString(const_descr->typeobj->tp_dict,
-					  const_descr->name, val);
-		Py_DECREF(val);
-		if (rv)
-			return NULL;
-	}
-
-	for (i = 0; gpiod_ModuleConsts[i].name; i++) {
-		mod_const = &gpiod_ModuleConsts[i];
-
-		rv = PyModule_AddIntConstant(module,
-					     mod_const->name, mod_const->value);
-		if (rv < 0)
-			return NULL;
-	}
-
-	rv = PyModule_AddStringConstant(module, "__version__",
-					gpiod_version_string());
-	if (rv < 0)
-		return NULL;
-
-	return module;
-}
diff --git a/bindings/python/tests/Makefile.am b/bindings/python/tests/Makefile.am
deleted file mode 100644
index 972b669..0000000
--- a/bindings/python/tests/Makefile.am
+++ /dev/null
@@ -1,13 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-or-later
-# SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
-
-dist_bin_SCRIPTS = gpiod_py_test.py
-
-pyexec_LTLIBRARIES = gpiomockup.la
-
-gpiomockup_la_SOURCES = gpiomockupmodule.c
-gpiomockup_la_CFLAGS = -I$(top_srcdir)/tests/mockup/
-gpiomockup_la_CFLAGS += -Wall -Wextra -g -std=gnu89 $(PYTHON_CPPFLAGS)
-gpiomockup_la_LDFLAGS = -module -avoid-version
-gpiomockup_la_LIBADD = $(top_builddir)/tests/mockup/libgpiomockup.la
-gpiomockup_la_LIBADD += $(PYTHON_LIBS)
diff --git a/bindings/python/tests/gpiod_py_test.py b/bindings/python/tests/gpiod_py_test.py
deleted file mode 100755
index f93c72c..0000000
--- a/bindings/python/tests/gpiod_py_test.py
+++ /dev/null
@@ -1,832 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-License-Identifier: GPL-2.0-or-later
-# SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
-
-import errno
-import gpiod
-import gpiomockup
-import os
-import select
-import time
-import threading
-import unittest
-
-from packaging import version
-
-mockup = None
-default_consumer = 'gpiod-py-test'
-
-class MockupTestCase(unittest.TestCase):
-
-    chip_sizes = None
-    flags = 0
-
-    def setUp(self):
-        mockup.probe(self.chip_sizes, flags=self.flags)
-
-    def tearDown(self):
-        mockup.remove()
-
-class EventThread(threading.Thread):
-
-    def __init__(self, chip_idx, line_offset, period_ms):
-        threading.Thread.__init__(self)
-        self.chip_idx = chip_idx
-        self.line_offset = line_offset
-        self.period_ms = period_ms
-        self.lock = threading.Lock()
-        self.cond = threading.Condition(self.lock)
-        self.should_stop = False
-
-    def run(self):
-        i = 0;
-        while True:
-            with self.lock:
-                if self.should_stop:
-                    break;
-
-                if not self.cond.wait(float(self.period_ms) / 1000):
-                    mockup.chip_set_pull(self.chip_idx,
-                                         self.line_offset, i % 2)
-                    i += 1
-
-    def stop(self):
-        with self.lock:
-            self.should_stop = True
-            self.cond.notify_all()
-
-    def __enter__(self):
-        self.start()
-        return self
-
-    def __exit__(self, exc_type, exc_value, traceback):
-        self.stop()
-        self.join()
-
-def check_kernel(major, minor, release):
-    current = os.uname().release.split('-')[0]
-    required = '{}.{}.{}'.format(major, minor, release)
-    if version.parse(current) < version.parse(required):
-        raise NotImplementedError(
-                'linux kernel version must be at least {} - got {}'.format(required, current))
-
-#
-# Chip test cases
-#
-
-class IsGpioDevice(MockupTestCase):
-
-    chip_sizes = ( 8, )
-
-    def test_is_gpiochip_device_good(self):
-        self.assertTrue(gpiod.is_gpiochip_device(mockup.chip_path(0)))
-
-    def test_is_gpiochip_device_bad(self):
-        self.assertFalse(gpiod.is_gpiochip_device('/dev/null'))
-
-    def test_is_gpiochip_device_nonexistent(self):
-        self.assertFalse(gpiod.is_gpiochip_device('/dev/nonexistent_device'))
-
-class ChipOpen(MockupTestCase):
-
-    chip_sizes = ( 8, 8, 8 )
-
-    def test_open_good(self):
-        with gpiod.Chip(mockup.chip_path(1)) as chip:
-            self.assertEqual(chip.name(), mockup.chip_name(1))
-
-    def test_nonexistent_chip(self):
-        with self.assertRaises(FileNotFoundError):
-            chip = gpiod.Chip('nonexistent-chip')
-
-    def test_open_chip_no_arguments(self):
-        with self.assertRaises(TypeError):
-            chip = gpiod.Chip()
-
-class ChipClose(MockupTestCase):
-
-    chip_sizes = ( 8, )
-
-    def test_use_chip_after_close(self):
-        chip = gpiod.Chip(mockup.chip_path(0))
-        self.assertEqual(chip.name(), mockup.chip_name(0))
-        chip.close()
-        with self.assertRaises(ValueError):
-            chip.name()
-
-class ChipInfo(MockupTestCase):
-
-    chip_sizes = ( 16, )
-
-    def test_chip_get_info(self):
-        chip = gpiod.Chip(mockup.chip_path(0))
-        self.assertEqual(chip.name(), mockup.chip_name(0))
-        self.assertEqual(chip.label(), 'gpio-mockup-A')
-        self.assertEqual(chip.num_lines(), 16)
-
-class ChipGetLines(MockupTestCase):
-
-    chip_sizes = ( 8, 8, 4 )
-    flags = gpiomockup.Mockup.FLAG_NAMED_LINES
-
-    def test_get_single_line_by_offset(self):
-        with gpiod.Chip(mockup.chip_path(1)) as chip:
-            line = chip.get_line(4)
-            self.assertEqual(line.name(), 'gpio-mockup-B-4')
-
-    def test_find_single_line_by_name(self):
-        with gpiod.Chip(mockup.chip_path(1)) as chip:
-            offset = chip.find_line('gpio-mockup-B-4')
-            self.assertIsNotNone(offset)
-            self.assertEqual(offset, 4)
-
-    def test_get_single_line_invalid_offset(self):
-        with gpiod.Chip(mockup.chip_path(1)) as chip:
-            with self.assertRaises(OSError) as err_ctx:
-                line = chip.get_line(11)
-
-            self.assertEqual(err_ctx.exception.errno, errno.EINVAL)
-
-    def test_find_single_line_nonexistent(self):
-        with gpiod.Chip(mockup.chip_path(1)) as chip:
-            offset = chip.find_line('nonexistent-line')
-            self.assertIsNone(offset)
-
-    def test_get_multiple_lines_by_offsets_in_tuple(self):
-        with gpiod.Chip(mockup.chip_path(1)) as chip:
-            lines = chip.get_lines(( 1, 3, 6, 7 )).to_list()
-            self.assertEqual(len(lines), 4)
-            self.assertEqual(lines[0].name(), 'gpio-mockup-B-1')
-            self.assertEqual(lines[1].name(), 'gpio-mockup-B-3')
-            self.assertEqual(lines[2].name(), 'gpio-mockup-B-6')
-            self.assertEqual(lines[3].name(), 'gpio-mockup-B-7')
-
-    def test_get_multiple_lines_by_offsets_in_list(self):
-        with gpiod.Chip(mockup.chip_path(1)) as chip:
-            lines = chip.get_lines([ 1, 3, 6, 7 ]).to_list()
-            self.assertEqual(len(lines), 4)
-            self.assertEqual(lines[0].name(), 'gpio-mockup-B-1')
-            self.assertEqual(lines[1].name(), 'gpio-mockup-B-3')
-            self.assertEqual(lines[2].name(), 'gpio-mockup-B-6')
-            self.assertEqual(lines[3].name(), 'gpio-mockup-B-7')
-
-    def test_get_multiple_lines_invalid_offset(self):
-        with gpiod.Chip(mockup.chip_path(1)) as chip:
-            with self.assertRaises(OSError) as err_ctx:
-                line = chip.get_lines(( 1, 3, 11, 7 ))
-
-            self.assertEqual(err_ctx.exception.errno, errno.EINVAL)
-
-    def test_get_all_lines(self):
-        with gpiod.Chip(mockup.chip_path(2)) as chip:
-            lines = chip.get_all_lines().to_list()
-            self.assertEqual(len(lines), 4)
-            self.assertEqual(lines[0].name(), 'gpio-mockup-C-0')
-            self.assertEqual(lines[1].name(), 'gpio-mockup-C-1')
-            self.assertEqual(lines[2].name(), 'gpio-mockup-C-2')
-            self.assertEqual(lines[3].name(), 'gpio-mockup-C-3')
-
-#
-# Line test cases
-#
-
-class LineInfo(MockupTestCase):
-
-    chip_sizes = ( 8, )
-    flags = gpiomockup.Mockup.FLAG_NAMED_LINES
-
-    def test_unexported_line(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(4)
-            self.assertEqual(line.offset(), 4)
-            self.assertEqual(line.name(), 'gpio-mockup-A-4')
-            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_INPUT)
-            self.assertFalse(line.is_active_low())
-            self.assertEqual(line.consumer(), None)
-            self.assertFalse(line.is_used())
-
-    def test_exported_line(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(4)
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_DIR_OUT,
-                         flags=gpiod.LINE_REQ_FLAG_ACTIVE_LOW)
-            self.assertEqual(line.offset(), 4)
-            self.assertEqual(line.name(), 'gpio-mockup-A-4')
-            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
-            self.assertTrue(line.is_active_low())
-            self.assertEqual(line.consumer(), default_consumer)
-            self.assertTrue(line.is_used())
-
-    def test_exported_line_with_flags(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(4)
-            flags = (gpiod.LINE_REQ_FLAG_ACTIVE_LOW |
-                     gpiod.LINE_REQ_FLAG_OPEN_DRAIN)
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_DIR_OUT,
-                         flags=flags)
-            self.assertEqual(line.offset(), 4)
-            self.assertEqual(line.name(), 'gpio-mockup-A-4')
-            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
-            self.assertTrue(line.is_active_low())
-            self.assertEqual(line.consumer(), default_consumer)
-            self.assertTrue(line.is_used())
-            self.assertEqual(line.drive(), gpiod.Line.DRIVE_OPEN_DRAIN)
-            self.assertEqual(line.bias(), gpiod.Line.BIAS_UNKNOWN)
-
-    def test_exported_open_drain_line(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(4)
-            flags = gpiod.LINE_REQ_FLAG_OPEN_DRAIN
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_DIR_OUT,
-                         flags=flags)
-            self.assertEqual(line.offset(), 4)
-            self.assertEqual(line.name(), 'gpio-mockup-A-4')
-            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
-            self.assertFalse(line.is_active_low())
-            self.assertEqual(line.consumer(), default_consumer)
-            self.assertTrue(line.is_used())
-            self.assertEqual(line.drive(), gpiod.Line.DRIVE_OPEN_DRAIN)
-            self.assertEqual(line.bias(), gpiod.Line.BIAS_UNKNOWN)
-
-    def test_exported_open_source_line(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(4)
-            flags = gpiod.LINE_REQ_FLAG_OPEN_SOURCE
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_DIR_OUT,
-                         flags=flags)
-            self.assertEqual(line.offset(), 4)
-            self.assertEqual(line.name(), 'gpio-mockup-A-4')
-            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
-            self.assertFalse(line.is_active_low())
-            self.assertEqual(line.consumer(), default_consumer)
-            self.assertTrue(line.is_used())
-            self.assertEqual(line.drive(), gpiod.Line.DRIVE_OPEN_SOURCE)
-            self.assertEqual(line.bias(), gpiod.Line.BIAS_UNKNOWN)
-
-    def test_exported_bias_disable_line(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(4)
-            flags = gpiod.LINE_REQ_FLAG_BIAS_DISABLED
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_DIR_OUT,
-                         flags=flags)
-            self.assertEqual(line.offset(), 4)
-            self.assertEqual(line.name(), 'gpio-mockup-A-4')
-            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
-            self.assertFalse(line.is_active_low())
-            self.assertEqual(line.consumer(), default_consumer)
-            self.assertTrue(line.is_used())
-            self.assertEqual(line.drive(), gpiod.Line.DRIVE_PUSH_PULL)
-            self.assertEqual(line.bias(), gpiod.Line.BIAS_DISABLED)
-
-    def test_exported_bias_pull_down_line(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(4)
-            flags = gpiod.LINE_REQ_FLAG_BIAS_PULL_DOWN
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_DIR_OUT,
-                         flags=flags)
-            self.assertEqual(line.offset(), 4)
-            self.assertEqual(line.name(), 'gpio-mockup-A-4')
-            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
-            self.assertFalse(line.is_active_low())
-            self.assertEqual(line.consumer(), default_consumer)
-            self.assertTrue(line.is_used())
-            self.assertEqual(line.drive(), gpiod.Line.DRIVE_PUSH_PULL)
-            self.assertEqual(line.bias(), gpiod.Line.BIAS_PULL_DOWN)
-
-    def test_exported_bias_pull_up_line(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(4)
-            flags = gpiod.LINE_REQ_FLAG_BIAS_PULL_UP
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_DIR_OUT,
-                         flags=flags)
-            self.assertEqual(line.offset(), 4)
-            self.assertEqual(line.name(), 'gpio-mockup-A-4')
-            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
-            self.assertFalse(line.is_active_low())
-            self.assertEqual(line.consumer(), default_consumer)
-            self.assertTrue(line.is_used())
-            self.assertEqual(line.drive(), gpiod.Line.DRIVE_PUSH_PULL)
-            self.assertEqual(line.bias(), gpiod.Line.BIAS_PULL_UP)
-
-class LineValues(MockupTestCase):
-
-    chip_sizes = ( 8, )
-
-    def test_get_value_single_line(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(3)
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_DIR_IN)
-            self.assertEqual(line.get_value(), 0)
-            mockup.chip_set_pull(0, 3, 1)
-            self.assertEqual(line.get_value(), 1)
-
-    def test_set_value_single_line(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(3)
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_DIR_OUT)
-            line.set_value(1)
-            self.assertEqual(mockup.chip_get_value(0, 3), 1)
-            line.set_value(0)
-            self.assertEqual(mockup.chip_get_value(0, 3), 0)
-
-    def test_set_value_with_default_value_argument(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(3)
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_DIR_OUT,
-                         default_val=1)
-            self.assertEqual(mockup.chip_get_value(0, 3), 1)
-
-    def test_get_value_multiple_lines(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            lines = chip.get_lines(( 0, 3, 4, 6 ))
-            lines.request(consumer=default_consumer,
-                          type=gpiod.LINE_REQ_DIR_IN)
-            self.assertEqual(lines.get_values(), [ 0, 0, 0, 0 ])
-            mockup.chip_set_pull(0, 0, 1)
-            mockup.chip_set_pull(0, 4, 1)
-            mockup.chip_set_pull(0, 6, 1)
-            self.assertEqual(lines.get_values(), [ 1, 0, 1, 1 ])
-
-    def test_set_value_multiple_lines(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            lines = chip.get_lines(( 0, 3, 4, 6 ))
-            lines.request(consumer=default_consumer,
-                          type=gpiod.LINE_REQ_DIR_OUT)
-            lines.set_values(( 1, 0, 1, 1 ))
-            self.assertEqual(mockup.chip_get_value(0, 0), 1)
-            self.assertEqual(mockup.chip_get_value(0, 3), 0)
-            self.assertEqual(mockup.chip_get_value(0, 4), 1)
-            self.assertEqual(mockup.chip_get_value(0, 6), 1)
-            lines.set_values(( 0, 0, 1, 0 ))
-            self.assertEqual(mockup.chip_get_value(0, 0), 0)
-            self.assertEqual(mockup.chip_get_value(0, 3), 0)
-            self.assertEqual(mockup.chip_get_value(0, 4), 1)
-            self.assertEqual(mockup.chip_get_value(0, 6), 0)
-
-    def test_set_multiple_values_with_default_vals_argument(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            lines = chip.get_lines(( 0, 3, 4, 6 ))
-            lines.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_DIR_OUT,
-                         default_vals=( 1, 0, 1, 1 ))
-            self.assertEqual(mockup.chip_get_value(0, 0), 1)
-            self.assertEqual(mockup.chip_get_value(0, 3), 0)
-            self.assertEqual(mockup.chip_get_value(0, 4), 1)
-            self.assertEqual(mockup.chip_get_value(0, 6), 1)
-
-    def test_get_value_active_low(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(3)
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_DIR_IN,
-                         flags=gpiod.LINE_REQ_FLAG_ACTIVE_LOW)
-            self.assertEqual(line.get_value(), 1)
-            mockup.chip_set_pull(0, 3, 1)
-            self.assertEqual(line.get_value(), 0)
-
-    def test_set_value_active_low(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(3)
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_DIR_OUT,
-                         flags=gpiod.LINE_REQ_FLAG_ACTIVE_LOW)
-            line.set_value(1)
-            self.assertEqual(mockup.chip_get_value(0, 3), 0)
-            line.set_value(0)
-            self.assertEqual(mockup.chip_get_value(0, 3), 1)
-
-class LineConfig(MockupTestCase):
-
-    chip_sizes = ( 8, )
-
-    def test_set_config_direction(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(3)
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_DIR_IN)
-            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_INPUT)
-            line.set_config(gpiod.LINE_REQ_DIR_IN, 0, 0)
-            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_INPUT)
-            line.set_config(gpiod.LINE_REQ_DIR_OUT,0,0)
-            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
-
-    def test_set_config_flags(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(3)
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_DIR_OUT)
-            line.set_config(gpiod.LINE_REQ_DIR_OUT,
-                            gpiod.LINE_REQ_FLAG_ACTIVE_LOW, 0)
-            self.assertEqual(mockup.chip_get_value(0, 3), 1)
-            line.set_config(gpiod.LINE_REQ_DIR_OUT, 0, 0)
-            self.assertEqual(mockup.chip_get_value(0, 3), 0)
-
-    def test_set_config_output_value(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(3)
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_DIR_IN)
-            line.set_config(gpiod.LINE_REQ_DIR_OUT,0,1)
-            self.assertEqual(mockup.chip_get_value(0, 3), 1)
-            line.set_config(gpiod.LINE_REQ_DIR_OUT,0,0)
-            self.assertEqual(mockup.chip_get_value(0, 3), 0)
-
-    def test_set_config_output_no_value(self):
-         with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(3)
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_DIR_OUT,
-                         default_val=1)
-            self.assertEqual(mockup.chip_get_value(0, 3), 1)
-            line.set_config(gpiod.LINE_REQ_DIR_OUT,0)
-            self.assertEqual(mockup.chip_get_value(0, 3), 0)
-
-    def test_set_config_bulk_output_no_values(self):
-         with gpiod.Chip(mockup.chip_path(0)) as chip:
-            lines = chip.get_lines(( 0, 3, 4, 6 ))
-            lines.request(consumer=default_consumer,
-                          type=gpiod.LINE_REQ_DIR_OUT,
-                          default_vals=(1,1,1,1))
-            self.assertEqual(mockup.chip_get_value(0, 0), 1)
-            self.assertEqual(mockup.chip_get_value(0, 3), 1)
-            self.assertEqual(mockup.chip_get_value(0, 4), 1)
-            self.assertEqual(mockup.chip_get_value(0, 6), 1)
-            lines.set_config(gpiod.LINE_REQ_DIR_OUT,0)
-            self.assertEqual(mockup.chip_get_value(0, 0), 0)
-            self.assertEqual(mockup.chip_get_value(0, 3), 0)
-            self.assertEqual(mockup.chip_get_value(0, 4), 0)
-            self.assertEqual(mockup.chip_get_value(0, 6), 0)
-
-class LineFlags(MockupTestCase):
-
-    chip_sizes = ( 8, )
-
-    def test_set_flags(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(3)
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_DIR_OUT,
-                         default_val=1)
-            self.assertEqual(mockup.chip_get_value(0, 3), 1)
-            line.set_flags(gpiod.LINE_REQ_FLAG_ACTIVE_LOW)
-            self.assertEqual(mockup.chip_get_value(0, 3), 0)
-            line.set_flags(0)
-            self.assertEqual(mockup.chip_get_value(0, 3), 1)
-
-    def test_set_flags_bulk(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            lines = chip.get_lines(( 0, 3, 4, 6 ))
-            lines.request(consumer=default_consumer,
-                          type=gpiod.LINE_REQ_DIR_OUT,
-                          default_vals=(1,1,1,1))
-            self.assertEqual(mockup.chip_get_value(0, 0), 1)
-            self.assertEqual(mockup.chip_get_value(0, 3), 1)
-            self.assertEqual(mockup.chip_get_value(0, 4), 1)
-            self.assertEqual(mockup.chip_get_value(0, 6), 1)
-            lines.set_flags(gpiod.LINE_REQ_FLAG_ACTIVE_LOW)
-            self.assertEqual(mockup.chip_get_value(0, 0), 0)
-            self.assertEqual(mockup.chip_get_value(0, 3), 0)
-            self.assertEqual(mockup.chip_get_value(0, 4), 0)
-            self.assertEqual(mockup.chip_get_value(0, 6), 0)
-            lines.set_flags(0)
-            self.assertEqual(mockup.chip_get_value(0, 0), 1)
-            self.assertEqual(mockup.chip_get_value(0, 3), 1)
-            self.assertEqual(mockup.chip_get_value(0, 4), 1)
-            self.assertEqual(mockup.chip_get_value(0, 6), 1)
-
-class LineDirection(MockupTestCase):
-
-    chip_sizes = ( 8, )
-
-    def test_set_direction(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(3)
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_DIR_OUT)
-            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
-            line.set_direction_input()
-            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_INPUT)
-            line.set_direction_output(0)
-            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
-            self.assertEqual(mockup.chip_get_value(0, 3), 0)
-            line.set_direction_output(1)
-            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
-            self.assertEqual(mockup.chip_get_value(0, 3), 1)
-            line.set_direction_output()
-            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
-            self.assertEqual(mockup.chip_get_value(0, 3), 0)
-
-    def test_set_direction_bulk(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            lines = chip.get_lines(( 0, 3, 4, 6 ))
-            lines.request(consumer=default_consumer,
-                          type=gpiod.LINE_REQ_DIR_OUT)
-            self.assertEqual(lines.to_list()[0].direction(),
-                             gpiod.Line.DIRECTION_OUTPUT)
-            self.assertEqual(lines.to_list()[1].direction(),
-                             gpiod.Line.DIRECTION_OUTPUT)
-            self.assertEqual(lines.to_list()[2].direction(),
-                             gpiod.Line.DIRECTION_OUTPUT)
-            self.assertEqual(lines.to_list()[3].direction(),
-                             gpiod.Line.DIRECTION_OUTPUT)
-            lines.set_direction_input()
-            self.assertEqual(lines.to_list()[0].direction(),
-                             gpiod.Line.DIRECTION_INPUT)
-            self.assertEqual(lines.to_list()[1].direction(),
-                             gpiod.Line.DIRECTION_INPUT)
-            self.assertEqual(lines.to_list()[2].direction(),
-                             gpiod.Line.DIRECTION_INPUT)
-            self.assertEqual(lines.to_list()[3].direction(),
-                             gpiod.Line.DIRECTION_INPUT)
-            lines.set_direction_output((0,0,1,0))
-            self.assertEqual(lines.to_list()[0].direction(),
-                             gpiod.Line.DIRECTION_OUTPUT)
-            self.assertEqual(lines.to_list()[1].direction(),
-                             gpiod.Line.DIRECTION_OUTPUT)
-            self.assertEqual(lines.to_list()[2].direction(),
-                             gpiod.Line.DIRECTION_OUTPUT)
-            self.assertEqual(lines.to_list()[3].direction(),
-                             gpiod.Line.DIRECTION_OUTPUT)
-            self.assertEqual(mockup.chip_get_value(0, 0), 0)
-            self.assertEqual(mockup.chip_get_value(0, 3), 0)
-            self.assertEqual(mockup.chip_get_value(0, 4), 1)
-            self.assertEqual(mockup.chip_get_value(0, 6), 0)
-            lines.set_direction_output((1,1,1,0))
-            self.assertEqual(lines.to_list()[0].direction(),
-                             gpiod.Line.DIRECTION_OUTPUT)
-            self.assertEqual(lines.to_list()[1].direction(),
-                             gpiod.Line.DIRECTION_OUTPUT)
-            self.assertEqual(lines.to_list()[2].direction(),
-                             gpiod.Line.DIRECTION_OUTPUT)
-            self.assertEqual(lines.to_list()[3].direction(),
-                             gpiod.Line.DIRECTION_OUTPUT)
-            self.assertEqual(mockup.chip_get_value(0, 0), 1)
-            self.assertEqual(mockup.chip_get_value(0, 3), 1)
-            self.assertEqual(mockup.chip_get_value(0, 4), 1)
-            self.assertEqual(mockup.chip_get_value(0, 6), 0)
-            lines.set_direction_output()
-            self.assertEqual(lines.to_list()[0].direction(),
-                             gpiod.Line.DIRECTION_OUTPUT)
-            self.assertEqual(lines.to_list()[1].direction(),
-                             gpiod.Line.DIRECTION_OUTPUT)
-            self.assertEqual(lines.to_list()[2].direction(),
-                             gpiod.Line.DIRECTION_OUTPUT)
-            self.assertEqual(lines.to_list()[3].direction(),
-                             gpiod.Line.DIRECTION_OUTPUT)
-            self.assertEqual(mockup.chip_get_value(0, 0), 0)
-            self.assertEqual(mockup.chip_get_value(0, 3), 0)
-            self.assertEqual(mockup.chip_get_value(0, 4), 0)
-            self.assertEqual(mockup.chip_get_value(0, 6), 0)
-
-class LineRequestBehavior(MockupTestCase):
-
-    chip_sizes = ( 8, )
-
-    def test_line_request_twice_two_calls(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(3)
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_DIR_IN)
-            with self.assertRaises(OSError) as err_ctx:
-                line.request(consumer=default_consumer,
-                             type=gpiod.LINE_REQ_DIR_IN)
-
-            self.assertEqual(err_ctx.exception.errno, errno.EBUSY)
-
-    def test_line_request_twice_in_bulk(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            lines = chip.get_lines(( 2, 3, 6, 6 ))
-            with self.assertRaises(OSError) as err_ctx:
-                lines.request(consumer=default_consumer,
-                              type=gpiod.LINE_REQ_DIR_IN)
-
-            self.assertEqual(err_ctx.exception.errno, errno.EBUSY)
-
-    def test_use_value_unrequested(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(3)
-            with self.assertRaises(OSError) as err_ctx:
-                line.get_value()
-
-            self.assertEqual(err_ctx.exception.errno, errno.EPERM)
-
-    def test_request_with_no_kwds(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(2)
-            line.request(default_consumer)
-            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_INPUT)
-            line.release()
-
-#
-# Iterator test cases
-#
-
-class LineIterator(MockupTestCase):
-
-    chip_sizes = ( 4, )
-
-    def test_iterate_over_lines(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            count = 0
-
-            for line in gpiod.LineIter(chip):
-                self.assertEqual(line.offset(), count)
-                count += 1
-
-            self.assertEqual(count, chip.num_lines())
-
-#
-# Event test cases
-#
-
-class EventSingleLine(MockupTestCase):
-
-    chip_sizes = ( 8, )
-
-    def test_single_line_rising_edge_event(self):
-        with EventThread(0, 4, 200):
-            with gpiod.Chip(mockup.chip_path(0)) as chip:
-                line = chip.get_line(4)
-                line.request(consumer=default_consumer,
-                             type=gpiod.LINE_REQ_EV_RISING_EDGE)
-                self.assertTrue(line.event_wait(sec=1))
-                event = line.event_read()
-                self.assertEqual(event.type, gpiod.LineEvent.RISING_EDGE)
-                self.assertEqual(event.source.offset(), 4)
-
-    def test_single_line_falling_edge_event(self):
-        with EventThread(0, 4, 200):
-            with gpiod.Chip(mockup.chip_path(0)) as chip:
-                line = chip.get_line(4)
-                line.request(consumer=default_consumer,
-                             type=gpiod.LINE_REQ_EV_FALLING_EDGE)
-                self.assertTrue(line.event_wait(sec=1))
-                event = line.event_read()
-                self.assertEqual(event.type, gpiod.LineEvent.FALLING_EDGE)
-                self.assertEqual(event.source.offset(), 4)
-
-    def test_single_line_both_edges_events(self):
-        with EventThread(0, 4, 200):
-            with gpiod.Chip(mockup.chip_path(0)) as chip:
-                line = chip.get_line(4)
-                line.request(consumer=default_consumer,
-                             type=gpiod.LINE_REQ_EV_BOTH_EDGES)
-                self.assertTrue(line.event_wait(sec=1))
-                event = line.event_read()
-                self.assertEqual(event.type, gpiod.LineEvent.RISING_EDGE)
-                self.assertEqual(event.source.offset(), 4)
-                self.assertTrue(line.event_wait(sec=1))
-                event = line.event_read()
-                self.assertEqual(event.type, gpiod.LineEvent.FALLING_EDGE)
-                self.assertEqual(event.source.offset(), 4)
-
-    def test_single_line_both_edges_events_active_low(self):
-        with EventThread(0, 4, 200):
-            with gpiod.Chip(mockup.chip_path(0)) as chip:
-                line = chip.get_line(4)
-                line.request(consumer=default_consumer,
-                             type=gpiod.LINE_REQ_EV_BOTH_EDGES,
-                             flags=gpiod.LINE_REQ_FLAG_ACTIVE_LOW)
-                self.assertTrue(line.event_wait(sec=1))
-                event = line.event_read()
-                self.assertEqual(event.type, gpiod.LineEvent.FALLING_EDGE)
-                self.assertEqual(event.source.offset(), 4)
-                self.assertTrue(line.event_wait(sec=1))
-                event = line.event_read()
-                self.assertEqual(event.type, gpiod.LineEvent.RISING_EDGE)
-                self.assertEqual(event.source.offset(), 4)
-
-    def test_single_line_read_multiple_events(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(4)
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_EV_BOTH_EDGES)
-            mockup.chip_set_pull(0, 4, 1)
-            time.sleep(0.01)
-            mockup.chip_set_pull(0, 4, 0)
-            time.sleep(0.01)
-            mockup.chip_set_pull(0, 4, 1)
-            time.sleep(0.01)
-            self.assertTrue(line.event_wait(sec=1))
-            events = line.event_read_multiple()
-            self.assertEqual(len(events), 3)
-            self.assertEqual(events[0].type, gpiod.LineEvent.RISING_EDGE)
-            self.assertEqual(events[1].type, gpiod.LineEvent.FALLING_EDGE)
-            self.assertEqual(events[2].type, gpiod.LineEvent.RISING_EDGE)
-            self.assertEqual(events[0].source.offset(), 4)
-            self.assertEqual(events[1].source.offset(), 4)
-            self.assertEqual(events[2].source.offset(), 4)
-
-class EventBulk(MockupTestCase):
-
-    chip_sizes = ( 8, )
-
-    def test_watch_multiple_lines_for_events(self):
-        with EventThread(0, 2, 200):
-            with gpiod.Chip(mockup.chip_path(0)) as chip:
-                lines = chip.get_lines(( 0, 1, 2, 3, 4 ))
-                lines.request(consumer=default_consumer,
-                              type=gpiod.LINE_REQ_EV_BOTH_EDGES)
-                event_lines = lines.event_wait(sec=1)
-                self.assertEqual(len(event_lines), 1)
-                line = event_lines[0]
-                event = line.event_read()
-                self.assertEqual(event.type, gpiod.LineEvent.RISING_EDGE)
-                self.assertEqual(event.source.offset(), 2)
-                event_lines = lines.event_wait(sec=1)
-                self.assertEqual(len(event_lines), 1)
-                line = event_lines[0]
-                event = line.event_read()
-                self.assertEqual(event.type, gpiod.LineEvent.FALLING_EDGE)
-                self.assertEqual(event.source.offset(), 2)
-
-class EventValues(MockupTestCase):
-
-    chip_sizes = ( 8, )
-
-    def test_request_for_events_get_value(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(3)
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_EV_BOTH_EDGES)
-            self.assertEqual(line.get_value(), 0)
-            mockup.chip_set_pull(0, 3, 1)
-            self.assertEqual(line.get_value(), 1)
-
-    def test_request_for_events_get_value_active_low(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(3)
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_EV_BOTH_EDGES,
-                         flags=gpiod.LINE_REQ_FLAG_ACTIVE_LOW)
-            self.assertEqual(line.get_value(), 1)
-            mockup.chip_set_pull(0, 3, 1)
-            self.assertEqual(line.get_value(), 0)
-
-class EventFileDescriptor(MockupTestCase):
-
-    chip_sizes = ( 8, )
-
-    def test_event_get_fd(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(3)
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_EV_BOTH_EDGES)
-            fd = line.event_get_fd();
-            self.assertGreaterEqual(fd, 0)
-
-    def test_event_get_fd_not_requested(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(3)
-            with self.assertRaises(OSError) as err_ctx:
-                fd = line.event_get_fd();
-
-            self.assertEqual(err_ctx.exception.errno, errno.EPERM)
-
-    def test_event_get_fd_requested_for_values(self):
-        with gpiod.Chip(mockup.chip_path(0)) as chip:
-            line = chip.get_line(3)
-            line.request(consumer=default_consumer,
-                         type=gpiod.LINE_REQ_DIR_IN)
-            with self.assertRaises(OSError) as err_ctx:
-                fd = line.event_get_fd();
-
-            self.assertEqual(err_ctx.exception.errno, errno.EPERM)
-
-    def test_event_fd_polling(self):
-        with EventThread(0, 2, 200):
-            with gpiod.Chip(mockup.chip_path(0)) as chip:
-                lines = chip.get_lines(( 0, 1, 2, 3, 4, 5, 6 ))
-                lines.request(consumer=default_consumer,
-                              type=gpiod.LINE_REQ_EV_BOTH_EDGES)
-
-                inputs = []
-                for line in lines:
-                    inputs.append(line.event_get_fd())
-
-                readable, writable, exceptional = select.select(inputs, [],
-                                                                inputs, 1.0)
-
-                self.assertEqual(len(readable), 1)
-                event = lines.to_list()[2].event_read()
-                self.assertEqual(event.type, gpiod.LineEvent.RISING_EDGE)
-                self.assertEqual(event.source.offset(), 2)
-
-#
-# Main
-#
-
-if __name__ == '__main__':
-    check_kernel(5, 10, 0)
-    mockup = gpiomockup.Mockup()
-    unittest.main()
diff --git a/bindings/python/tests/gpiomockupmodule.c b/bindings/python/tests/gpiomockupmodule.c
deleted file mode 100644
index 761d431..0000000
--- a/bindings/python/tests/gpiomockupmodule.c
+++ /dev/null
@@ -1,309 +0,0 @@
-// SPDX-License-Identifier: LGPL-2.1-or-later
-// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
-
-#include <Python.h>
-#include <gpio-mockup.h>
-
-typedef struct {
-	PyObject_HEAD
-	struct gpio_mockup *mockup;
-} gpiomockup_MockupObject;
-
-enum {
-	gpiomockup_FLAG_NAMED_LINES = 1,
-};
-
-static int gpiomockup_Mockup_init(gpiomockup_MockupObject *self,
-				  PyObject *Py_UNUSED(ignored0),
-				  PyObject *Py_UNUSED(ignored1))
-{
-	Py_BEGIN_ALLOW_THREADS;
-	self->mockup = gpio_mockup_new();
-	Py_END_ALLOW_THREADS;
-	if (!self->mockup) {
-		PyErr_SetFromErrno(PyExc_OSError);
-		return -1;
-	}
-
-	return 0;
-}
-
-static void gpiomockup_Mockup_dealloc(gpiomockup_MockupObject *self)
-{
-	if (self->mockup) {
-		Py_BEGIN_ALLOW_THREADS;
-		gpio_mockup_unref(self->mockup);
-		Py_END_ALLOW_THREADS;
-	}
-
-	PyObject_Del(self);
-}
-
-static PyObject *gpiomockup_Mockup_probe(gpiomockup_MockupObject *self,
-					 PyObject *args, PyObject *kwds)
-{
-	static char *kwlist[] = { "chip_sizes",
-				  "flags",
-				  NULL };
-
-	PyObject *chip_sizes_obj, *iter, *next;
-	unsigned int *chip_sizes;
-	int ret, flags = 0, i;
-	Py_ssize_t num_chips;
-
-	ret = PyArg_ParseTupleAndKeywords(args, kwds, "O|i", kwlist,
-					  &chip_sizes_obj, &flags);
-	if (!ret)
-		return NULL;
-
-	num_chips = PyObject_Size(chip_sizes_obj);
-	if (num_chips < 0) {
-		return NULL;
-	} else if (num_chips == 0) {
-		PyErr_SetString(PyExc_TypeError,
-				"Number of chips must be greater thatn 0");
-		return NULL;
-	}
-
-	chip_sizes = PyMem_RawCalloc(num_chips, sizeof(unsigned int));
-	if (!chip_sizes)
-		return NULL;
-
-	iter = PyObject_GetIter(chip_sizes_obj);
-	if (!iter) {
-		PyMem_RawFree(chip_sizes);
-		return NULL;
-	}
-
-	for (i = 0;; i++) {
-		next = PyIter_Next(iter);
-		if (!next) {
-			Py_DECREF(iter);
-			break;
-		}
-
-		chip_sizes[i] = PyLong_AsUnsignedLong(next);
-		Py_DECREF(next);
-		if (PyErr_Occurred()) {
-			Py_DECREF(iter);
-			PyMem_RawFree(chip_sizes);
-			return NULL;
-		}
-	}
-
-	if (flags & gpiomockup_FLAG_NAMED_LINES)
-		flags |= GPIO_MOCKUP_FLAG_NAMED_LINES;
-
-	Py_BEGIN_ALLOW_THREADS;
-	ret = gpio_mockup_probe(self->mockup, num_chips, chip_sizes, flags);
-	Py_END_ALLOW_THREADS;
-	PyMem_RawFree(chip_sizes);
-	if (ret)
-		return NULL;
-
-	Py_RETURN_NONE;
-}
-
-static PyObject *gpiomockup_Mockup_remove(gpiomockup_MockupObject *self,
-					  PyObject *Py_UNUSED(ignored))
-{
-	int ret;
-
-	Py_BEGIN_ALLOW_THREADS;
-	ret = gpio_mockup_remove(self->mockup);
-	Py_END_ALLOW_THREADS;
-	if (ret) {
-		PyErr_SetFromErrno(PyExc_OSError);
-		return NULL;
-	}
-
-	Py_RETURN_NONE;
-}
-
-static PyObject *gpiomockup_Mockup_chip_name(gpiomockup_MockupObject *self,
-					     PyObject *args)
-{
-	unsigned int idx;
-	const char *name;
-	int ret;
-
-	ret = PyArg_ParseTuple(args, "I", &idx);
-	if (!ret)
-		return NULL;
-
-	name = gpio_mockup_chip_name(self->mockup, idx);
-	if (!name) {
-		PyErr_SetFromErrno(PyExc_OSError);
-		return NULL;
-	}
-
-	return PyUnicode_FromString(name);
-}
-
-static PyObject *gpiomockup_Mockup_chip_path(gpiomockup_MockupObject *self,
-					     PyObject *args)
-{
-	unsigned int idx;
-	const char *path;
-	int ret;
-
-	ret = PyArg_ParseTuple(args, "I", &idx);
-	if (!ret)
-		return NULL;
-
-	path = gpio_mockup_chip_path(self->mockup, idx);
-	if (!path) {
-		PyErr_SetFromErrno(PyExc_OSError);
-		return NULL;
-	}
-
-	return PyUnicode_FromString(path);
-}
-
-static PyObject *gpiomockup_Mockup_chip_num(gpiomockup_MockupObject *self,
-					     PyObject *args)
-{
-	unsigned int idx;
-	int ret, num;
-
-	ret = PyArg_ParseTuple(args, "I", &idx);
-	if (!ret)
-		return NULL;
-
-	num = gpio_mockup_chip_num(self->mockup, idx);
-	if (num < 0) {
-		PyErr_SetFromErrno(PyExc_OSError);
-		return NULL;
-	}
-
-	return PyLong_FromLong(num);
-}
-
-static PyObject *gpiomockup_Mockup_chip_get_value(gpiomockup_MockupObject *self,
-						  PyObject *args)
-{
-	unsigned int chip_idx, line_offset;
-	int ret, val;
-
-	ret = PyArg_ParseTuple(args, "II", &chip_idx, &line_offset);
-	if (!ret)
-		return NULL;
-
-	Py_BEGIN_ALLOW_THREADS;
-	val = gpio_mockup_get_value(self->mockup, chip_idx, line_offset);
-	Py_END_ALLOW_THREADS;
-	if (val < 0) {
-		PyErr_SetFromErrno(PyExc_OSError);
-		return NULL;
-	}
-
-	return PyLong_FromUnsignedLong(val);
-}
-
-static PyObject *gpiomockup_Mockup_chip_set_pull(gpiomockup_MockupObject *self,
-						 PyObject *args)
-{
-	unsigned int chip_idx, line_offset;
-	int ret, pull;
-
-	ret = PyArg_ParseTuple(args, "IIi", &chip_idx, &line_offset, &pull);
-	if (!ret)
-		return NULL;
-
-	Py_BEGIN_ALLOW_THREADS;
-	ret = gpio_mockup_set_pull(self->mockup, chip_idx, line_offset, pull);
-	Py_END_ALLOW_THREADS;
-	if (ret) {
-		PyErr_SetFromErrno(PyExc_OSError);
-		return NULL;
-	}
-
-	Py_RETURN_NONE;
-}
-
-static PyMethodDef gpiomockup_Mockup_methods[] = {
-	{
-		.ml_name = "probe",
-		.ml_meth = (PyCFunction)(void (*)(void))gpiomockup_Mockup_probe,
-		.ml_flags = METH_VARARGS | METH_KEYWORDS,
-	},
-	{
-		.ml_name = "remove",
-		.ml_meth = (PyCFunction)gpiomockup_Mockup_remove,
-		.ml_flags = METH_NOARGS,
-	},
-	{
-		.ml_name = "chip_name",
-		.ml_meth = (PyCFunction)gpiomockup_Mockup_chip_name,
-		.ml_flags = METH_VARARGS,
-	},
-	{
-		.ml_name = "chip_path",
-		.ml_meth = (PyCFunction)gpiomockup_Mockup_chip_path,
-		.ml_flags = METH_VARARGS,
-	},
-	{
-		.ml_name = "chip_num",
-		.ml_meth = (PyCFunction)gpiomockup_Mockup_chip_num,
-		.ml_flags = METH_VARARGS,
-	},
-	{
-		.ml_name = "chip_get_value",
-		.ml_meth = (PyCFunction)gpiomockup_Mockup_chip_get_value,
-		.ml_flags = METH_VARARGS,
-	},
-	{
-		.ml_name = "chip_set_pull",
-		.ml_meth = (PyCFunction)gpiomockup_Mockup_chip_set_pull,
-		.ml_flags = METH_VARARGS,
-	},
-	{ }
-};
-
-static PyTypeObject gpiomockup_MockupType = {
-	PyVarObject_HEAD_INIT(NULL, 0)
-	.tp_name = "gpiomockup.Mockup",
-	.tp_basicsize = sizeof(gpiomockup_MockupObject),
-	.tp_flags = Py_TPFLAGS_DEFAULT,
-	.tp_new = PyType_GenericNew,
-	.tp_init = (initproc)gpiomockup_Mockup_init,
-	.tp_dealloc = (destructor)gpiomockup_Mockup_dealloc,
-	.tp_methods = gpiomockup_Mockup_methods,
-};
-
-static PyModuleDef gpiomockup_Module = {
-	PyModuleDef_HEAD_INIT,
-	.m_name = "gpiomockup",
-	.m_size = -1,
-};
-
-PyMODINIT_FUNC PyInit_gpiomockup(void)
-{
-	PyObject *module, *val;
-	int ret;
-
-	module = PyModule_Create(&gpiomockup_Module);
-	if (!module)
-		return NULL;
-
-	ret = PyType_Ready(&gpiomockup_MockupType);
-	if (ret)
-		return NULL;
-	Py_INCREF(&gpiomockup_MockupType);
-
-	ret = PyModule_AddObject(module, "Mockup",
-				 (PyObject *)&gpiomockup_MockupType);
-	if (ret)
-		return NULL;
-
-	val = PyLong_FromLong(gpiomockup_FLAG_NAMED_LINES);
-	if (!val)
-		return NULL;
-
-	ret = PyDict_SetItemString(gpiomockup_MockupType.tp_dict,
-				   "FLAG_NAMED_LINES", val);
-	if (ret)
-		return NULL;
-
-	return module;
-}
-- 
2.34.1


  reply	other threads:[~2022-10-26 12:34 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-26 12:34 [libgpiod v2][PATCH v4 0/4] bindings: implement python bindings for libgpiod v2 Bartosz Golaszewski
2022-10-26 12:34 ` Bartosz Golaszewski [this message]
2022-10-26 12:34 ` [libgpiod v2][PATCH v4 2/4] bindings: python: add examples Bartosz Golaszewski
2022-10-26 12:53   ` Andy Shevchenko
2022-10-27  8:05     ` Bartosz Golaszewski
2022-10-26 12:34 ` [libgpiod v2][PATCH v4 3/4] bindings: python: add tests Bartosz Golaszewski
2022-10-26 12:34 ` [libgpiod v2][PATCH v4 4/4] bindings: python: implement python bindings for libgpiod v2 Bartosz Golaszewski
2022-10-31 11:41 ` [libgpiod v2][PATCH v4 0/4] bindings: " Bartosz Golaszewski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20221026123425.498912-2-brgl@bgdev.pl \
    --to=brgl@bgdev.pl \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=linus.walleij@linaro.org \
    --cc=linux-gpio@vger.kernel.org \
    --cc=viresh.kumar@linaro.org \
    --cc=warthog618@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.