Thanks Dean. Series applied to next-dts.
On Thu, Jan 22, 2026 at 12:47 PM Dean Marx <[email protected]> wrote: > > 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 <[email protected]> > Reviewed-by: Patrick Robb <[email protected]> > --- > devtools/dts-check-docstrings.py | 54 ++++++++++++++++++++++++++++++++ > devtools/dts-check-format.sh | 5 +++ > 2 files changed, 59 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..23c0a5f1da 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,10 @@ if $lint; then > echo "ruff not found, unable to run linter" > errors=$((errors + 1)) > fi > + if $docstringcheck; then > + python3 ../devtools/dts-check-docstrings.py > + errors=$((errors + $?)) > + fi > fi > > if $typecheck; then > -- > 2.52.0 >

