[PATCH v3] dts: add test case docstring checks to format script

Dean Marx dmarx at iol.unh.edu
Thu Nov 6 19:13:55 CET 2025


Add a python script that checks all test cases
to ensure each docstring contains a steps and
verify section in accordance with coding guidelines.
Add a section within the check-format script which
calls the docstring script after linting with ruff.

Bugzilla ID: 1623

Signed-off-by: Dean Marx <dmarx at iol.unh.edu>
---
 devtools/dts-check-docstrings.py | 54 ++++++++++++++++++++++++++++++++
 devtools/dts-check-format.sh     |  8 +++++
 2 files changed, 62 insertions(+)
 create mode 100755 devtools/dts-check-docstrings.py

diff --git a/devtools/dts-check-docstrings.py b/devtools/dts-check-docstrings.py
new file mode 100755
index 0000000000..3b0d2a42a1
--- /dev/null
+++ b/devtools/dts-check-docstrings.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2025 University of New Hampshire
+
+import sys
+from ast import FunctionDef, Name, walk, get_docstring, parse
+from pathlib import Path
+
+BASE_DIR = Path(__file__).resolve().parent.parent  # dpdk/
+TESTS_DIR = BASE_DIR / "dts" / "tests"  # dts/tests/
+DECORATOR_NAMES = {"func_test", "perf_test"}
+
+
+def has_test_decorator(node: FunctionDef) -> bool:
+    """Return True if function has @func_test or @perf_test decorator."""
+    for decorator in node.decorator_list:
+        if isinstance(decorator, Name) and decorator.id in DECORATOR_NAMES:
+            return True
+    return False
+
+
+def check_file(path: Path) -> bool:
+    """Return True if file has steps and verify sections in each test case docstring."""
+    source = path.read_text(encoding="utf-8")
+    tree = parse(source, filename=str(path))
+    ok = True
+
+    for node in walk(tree):
+        if isinstance(node, FunctionDef):
+            if has_test_decorator(node):
+                doc = get_docstring(node)
+                if not doc:
+                    print(f"{path}:{node.lineno} missing docstring for test case")
+                    ok = False
+                else:
+                    if "Steps:" not in doc:
+                        print(f"{path}:{node.lineno} missing 'Steps:' section")
+                        ok = False
+                    if "Verify:" not in doc:
+                        print(f"{path}:{node.lineno} missing 'Verify:' section")
+                        ok = False
+    return ok
+
+
+def main():
+    all_ok = True
+    for path in TESTS_DIR.rglob("*.py"):
+        if not check_file(path):
+            all_ok = False
+    sys.exit(0 if all_ok else 1)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/devtools/dts-check-format.sh b/devtools/dts-check-format.sh
index 907eed1293..f2cd5a56a1 100755
--- a/devtools/dts-check-format.sh
+++ b/devtools/dts-check-format.sh
@@ -13,6 +13,7 @@ usage() {
 format=true
 lint=true
 typecheck=true
+docstringcheck=true
 
 # Comments after args serve as documentation; must be present
 while getopts "hflt" arg; do
@@ -97,6 +98,13 @@ if $lint; then
 		echo "ruff not found, unable to run linter"
 		errors=$((errors + 1))
 	fi
+	if $docstringcheck; then
+		docstring_script_path=$(dirname "$0")
+		docstring_script_path=$(cd "$docstring_script_path" && pwd)
+		docstring_script="$docstring_script_path/dts-check-docstrings.py"
+		$docstring_script
+		errors=$((errors + $?))
+	fi
 fi
 
 if $typecheck; then
-- 
2.51.0



More information about the dev mailing list