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;
-}
