scripts: ci: add vermin (min python version check)

Add a compliance check that allows to flag when a given file requires a
Python version higher than 3.10 (minimum supported version in Zephyr at
the time of writing) since not all Python scripts are tested against
3.10 in CI and we want to avoid introducing changes that could break
users.

Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
This commit is contained in:
Benjamin Cabé 2025-06-03 11:00:16 +02:00 committed by Benjamin Cabé
commit 17ab862169
5 changed files with 67 additions and 0 deletions

1
.gitignore vendored
View file

@ -102,6 +102,7 @@ MaintainersFormat.txt
ModulesMaintainers.txt
Nits.txt
Pylint.txt
PythonCompat.txt
Ruff.txt
SphinxLint.txt
SysbuildKconfig.txt

View file

@ -1815,6 +1815,66 @@ class Ruff(ComplianceTest):
desc = f"Run 'ruff format {file}'"
self.fmtd_failure("error", "Python format error", file, desc=desc)
class PythonCompatCheck(ComplianceTest):
"""
Python Compatibility Check
"""
name = "PythonCompat"
doc = "Check that Python files are compatible with Zephyr minimum supported Python version."
MAX_VERSION = (3, 10)
MAX_VERSION_STR = f"{MAX_VERSION[0]}.{MAX_VERSION[1]}"
def run(self):
py_files = [f for f in get_files(filter="d") if f.endswith(".py")]
if not py_files:
return
cmd = ["vermin", "-f", "parsable", "--violations",
f"-t={self.MAX_VERSION_STR}", "--no-make-paths-absolute"] + py_files
try:
result = subprocess.run(cmd,
check=False,
capture_output=True,
cwd=GIT_TOP)
except Exception as ex:
self.error(f"Failed to run vermin: {ex}")
output = result.stdout.decode("utf-8")
failed = False
for line in output.splitlines():
parts = line.split(":")
if len(parts) < 6:
continue
filename, line_number, column, _, py3ver, feature = parts[:6]
if not line_number:
# Ignore all file-level messages
continue
desc = None
if py3ver.startswith('!'):
desc = f"{feature} is known to be incompatible with Python 3."
elif py3ver.startswith('~'):
# "no known reason it won't work", just skip
continue
else:
major, minor = map(int, py3ver.split(".")[:2])
if (major, minor) > self.MAX_VERSION:
desc = f"{feature} requires Python {major}.{minor}, which is higher than " \
f"Zephyr's minimum supported Python version ({self.MAX_VERSION_STR})."
if desc is not None:
self.fmtd_failure(
"error",
"PythonCompat",
filename,
line=int(line_number),
col=int(column) if column else None,
desc=desc,
)
failed = True
if failed:
self.failure("Some Python files use features that are not compatible with Python " \
f"{self.MAX_VERSION_STR}.")
class TextEncoding(ComplianceTest):
"""

View file

@ -35,6 +35,7 @@ tabulate
tomli>=1.1.0
tox
unidiff
vermin
west>=0.14.0
xlsxwriter
yamllint

View file

@ -1235,6 +1235,10 @@ urllib3==2.4.0 \
# elastic-transport
# pygithub
# requests
vermin==1.6.0 \
--hash=sha256:6266ca02f55d1c2aa189a610017c132eb2d1934f09e72a955b1eb3820ee6d4ef \
--hash=sha256:f1fa9ee40f59983dc40e0477eb2b1fa8061a3df4c3b2bcf349add462a5610efb
# via -r requirements-actions.in
virtualenv==20.31.2 \
--hash=sha256:36efd0d9650ee985f0cad72065001e66d49a6f24eb44d98980f630686243cf11 \
--hash=sha256:e10c0a9d02835e592521be48b332b6caee6887f332c111aa79a09b9e79efc2af

View file

@ -13,5 +13,6 @@ python-magic; sys_platform != "win32"
ruff==0.11.11
sphinx-lint
unidiff
vermin
yamllint
# zephyr-keep-sorted-stop