diff mbox series

[3/3] bindings: python: tests: provide and use system.check_kernel_version()

Message ID 20241120-drop-distutils-v1-3-7498e8b3babe@linaro.org
State New
Headers show
Series bindings: python: drop dependency on distutils | expand

Commit Message

Bartosz Golaszewski Nov. 20, 2024, 1:18 p.m. UTC
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

We claim that libgpiod python bindings have no dependencies other than
the python standard library but this is not true - the tests do depend
on deprecated distutils for kernel version parsing.

As distutils is deprecated, the recommended improvement is to use the
Version class from packaging.version but this would too entail pulling
in an external module.

Let's instead implement the kernel version check in C using uname() and
put it into the tests.system extension. This allows us to entirely drop
the distutils import.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 bindings/python/tests/__init__.py        | 11 +++++-----
 bindings/python/tests/system/__init__.py |  4 ++--
 bindings/python/tests/system/_ext.pyi    |  1 +
 bindings/python/tests/system/ext.c       | 37 ++++++++++++++++++++++++++++++++
 4 files changed, 45 insertions(+), 8 deletions(-)
diff mbox series

Patch

diff --git a/bindings/python/tests/__init__.py b/bindings/python/tests/__init__.py
index a0f22ae..3eb13f7 100644
--- a/bindings/python/tests/__init__.py
+++ b/bindings/python/tests/__init__.py
@@ -1,13 +1,12 @@ 
 # SPDX-License-Identifier: LGPL-2.1-or-later
 # SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
+# SPDX-FileCopyrightText: 2024 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
 
-import os
-from distutils.version import LooseVersion
+from .system import check_kernel_version
 
-required_kernel_version = LooseVersion("5.19.0")
-current_version = LooseVersion(os.uname().release.split("-")[0])
+_required_kernel_version = (5, 19, 0)
 
-if current_version < required_kernel_version:
+if not check_kernel_version(*_required_kernel_version):
     raise NotImplementedError(
-        f"linux kernel version must be at least {required_kernel_version} - got {current_version}"
+        f"linux kernel version must be at least v{'.'.join([str(i) for i in _required_kernel_version])}"
     )
diff --git a/bindings/python/tests/system/__init__.py b/bindings/python/tests/system/__init__.py
index 436ff40..cba9b92 100644
--- a/bindings/python/tests/system/__init__.py
+++ b/bindings/python/tests/system/__init__.py
@@ -1,6 +1,6 @@ 
 # SPDX-License-Identifier: GPL-2.0-or-later
 # SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
 
-from ._ext import set_process_name
+from ._ext import check_kernel_version, set_process_name
 
-__all__ = ["set_process_name"]
+__all__ = ["check_kernel_version", "set_process_name"]
diff --git a/bindings/python/tests/system/_ext.pyi b/bindings/python/tests/system/_ext.pyi
index df8bb15..0a19d6c 100644
--- a/bindings/python/tests/system/_ext.pyi
+++ b/bindings/python/tests/system/_ext.pyi
@@ -2,3 +2,4 @@ 
 # SPDX-FileCopyrightText: 2024 Vincent Fazio <vfazio@gmail.com>
 
 def set_process_name(name: str) -> None: ...
+def check_kernel_version(major: int, minor: int, release: int) -> bool: ...
diff --git a/bindings/python/tests/system/ext.c b/bindings/python/tests/system/ext.c
index e7c1cc4..c982fa6 100644
--- a/bindings/python/tests/system/ext.c
+++ b/bindings/python/tests/system/ext.c
@@ -1,8 +1,11 @@ 
 // SPDX-License-Identifier: LGPL-2.1-or-later
 // SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
+// SPDX-FileCopyrightText: 2024 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
 
 #include <Python.h>
+#include <linux/version.h>
 #include <sys/prctl.h>
+#include <sys/utsname.h>
 
 static PyObject *
 module_set_process_name(PyObject *Py_UNUSED(self), PyObject *args)
@@ -21,12 +24,46 @@  module_set_process_name(PyObject *Py_UNUSED(self), PyObject *args)
 	Py_RETURN_NONE;
 }
 
+static PyObject *
+module_check_kernel_version(PyObject *Py_UNUSED(self), PyObject *args)
+{
+	unsigned int req_maj, req_min, req_rel, curr_maj, curr_min, curr_rel;
+	struct utsname un;
+	int ret;
+
+	ret = PyArg_ParseTuple(args, "III", &req_maj, &req_min, &req_rel);
+	if (!ret)
+		return NULL;
+
+	ret = uname(&un);
+	if (ret)
+		return PyErr_SetFromErrno(PyExc_OSError);
+
+	ret = sscanf(un.release, "%u.%u.%u", &curr_maj, &curr_min, &curr_rel);
+	if (ret != 3) {
+		PyErr_SetString(PyExc_RuntimeError,
+				"invalid linux version read from the kernel");
+		return NULL;
+	}
+
+	if (KERNEL_VERSION(curr_maj, curr_min, curr_rel) <
+	    KERNEL_VERSION(req_maj, req_min, req_rel))
+		Py_RETURN_FALSE;
+
+	Py_RETURN_TRUE;
+}
+
 static PyMethodDef module_methods[] = {
 	{
 		.ml_name = "set_process_name",
 		.ml_meth = (PyCFunction)module_set_process_name,
 		.ml_flags = METH_VARARGS,
 	},
+	{
+		.ml_name = "check_kernel_version",
+		.ml_meth = (PyCFunction)module_check_kernel_version,
+		.ml_flags = METH_VARARGS,
+	},
 	{ }
 };