bindings: python: tests: provide and use system.check_kernel_version() master bb/master origin/HEAD origin/master
authorBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Wed, 20 Nov 2024 13:18:20 +0000 (14:18 +0100)
committerBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Mon, 25 Nov 2024 09:03:54 +0000 (10:03 +0100)
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.

Reviewed-by: Vincent Fazio <vfazio@xes-inc.com>
Link: https://lore.kernel.org/r/20241120-drop-distutils-v1-3-7498e8b3babe@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
bindings/python/tests/__init__.py
bindings/python/tests/system/__init__.py
bindings/python/tests/system/_ext.pyi
bindings/python/tests/system/ext.c

index a0f22ae717271766b4175a775cc6ec19c9b24441..3eb13f73b06d787767fefbe1210c18b3ca7c2d3c 100644 (file)
@@ -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])}"
     )
index 436ff406fec30f7711dd1bb3f95024a6c530d45a..cba9b92108bc3e34f0a5d241cfef6335c072409e 100644 (file)
@@ -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"]
index df8bb1551905135eb9489cae369ffd4d4fe08449..0a19d6c77994adab11eff2e3a3236ff882ea652f 100644 (file)
@@ -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: ...
index e7c1cc4f8cd064f4188e13f1ddb595d1fae1f48b..c982fa60763f74cc428c0cb6a96f8aa714972377 100644 (file)
@@ -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,
+       },
        { }
 };