WriteDocs() and write_bintool_docs() strip four characters from the start
of every docstring line but the first, to undo the indentation the source
file gives them. Since Python 3.13 the compiler already removes the common
indentation from docstrings [1], so this removes four characters of actual
text from every line of every entry and bintool description:

  $ binman entry-docs | head
  ...
   that an image node whose only content is an optional entry which was
   is an example showing ATF, TEE and a device tree all combined::

Use inspect.cleandoc() instead, which produces the same result on both
older and newer interpreters.

The existing tests only checked that some output was produced, so they
missed this entirely; make them also confirm that a known line of a known
description survives intact.

Link: https://github.com/python/cpython/issues/81283 [1]
Signed-off-by: Alexey Charkov <[email protected]>
---
 tools/binman/bintool.py |  6 ++++--
 tools/binman/entry.py   |  9 +++++++--
 tools/binman/ftest.py   | 19 +++++++++++++++++--
 3 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/tools/binman/bintool.py b/tools/binman/bintool.py
index 9c76c8881a46..4cf8d5b165bf 100644
--- a/tools/binman/bintool.py
+++ b/tools/binman/bintool.py
@@ -12,6 +12,7 @@ the tool, checking its version and fetching it if needed.
 import collections
 import glob
 import importlib
+import inspect
 import multiprocessing
 import os
 import shutil
@@ -463,9 +464,10 @@ binaries. It is fairly easy to create new bintools. Just 
add a new file to the
             if test_missing == name:
                 docs = None
             if docs:
-                lines = docs.splitlines()
+                # See the note in Entry.WriteDocs() about cleandoc()
+                lines = inspect.cleandoc(docs).splitlines()
                 first_line = lines[0]
-                rest = [line[4:] for line in lines[1:]]
+                rest = lines[1:]
                 hdr = 'Bintool: %s: %s' % (name, first_line)
                 print(hdr)
                 print('-' * len(hdr))
diff --git a/tools/binman/entry.py b/tools/binman/entry.py
index ce7ef28e94b1..9b39c7118892 100644
--- a/tools/binman/entry.py
+++ b/tools/binman/entry.py
@@ -6,6 +6,7 @@
 
 from collections import namedtuple
 import importlib
+import inspect
 import os
 import pathlib
 import sys
@@ -858,9 +859,13 @@ features to produce new behaviours.
             if test_missing == name:
                 docs = None
             if docs:
-                lines = docs.splitlines()
+                # Use cleandoc() rather than removing a fixed four characters
+                # of indent: since Python 3.13 the compiler already strips the
+                # common indent from docstrings, so doing it again here would
+                # eat the first four characters of every line
+                lines = inspect.cleandoc(docs).splitlines()
                 first_line = lines[0]
-                rest = [line[4:] for line in lines[1:]]
+                rest = lines[1:]
                 hdr = 'Entry: %s: %s' % (name.replace('_', '-'), first_line)
 
                 # Create a reference for use by rST docs
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 9553eb6b7366..c5c67c7e68b1 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -1805,7 +1805,15 @@ class TestFunctional(unittest.TestCase):
         """Test for creation of entry documentation"""
         with terminal.capture() as (stdout, stderr):
             control.WriteEntryDocs(control.GetEntryModules())
-        self.assertTrue(len(stdout.getvalue()) > 0)
+        out = stdout.getvalue()
+        self.assertTrue(len(out) > 0)
+
+        # The body of each docstring must come out dedented but otherwise
+        # intact. Check a heading which several etypes use, since truncating
+        # the indent by too much would silently eat the start of every line.
+        self.assertIn('\nProperties / Entry arguments:\n', out)
+        self.assertIn('\nEntry: atf-bl31: ARM Trusted Firmware (ATF) BL31 
blob\n',
+                      out)
 
     def testEntryDocsMissing(self):
         """Test handling of missing entry documentation"""
@@ -5491,7 +5499,14 @@ fdt         fdtmap                Extract the devicetree 
blob from the fdtmap
         """Test for creation of bintool documentation"""
         with terminal.capture() as (stdout, stderr):
             control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
-        self.assertTrue(len(stdout.getvalue()) > 0)
+        out = stdout.getvalue()
+        self.assertTrue(len(out) > 0)
+
+        # As in testEntryDocs(), check that the body is dedented but intact
+        self.assertIn('\nBintool: mkimage: Image generation for U-Boot\n', out)
+        self.assertIn(
+            '\nThis bintool supports running `mkimage` with some basic 
parameters as\n',
+            out)
 
     def testBintoolDocsMissing(self):
         """Test handling of missing bintool documentation"""

---
base-commit: 44f0dcf476140c1077ee3dbe16a80fdb6f8265c4
change-id: 20260730-b4-binman-docstring-dedent-84cc7a1007cd

Best regards,
--  
Alexey Charkov <[email protected]>

Reply via email to