]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-104683: Argument Clinic: refactor format_docstring() (#107623)
authorErlend E. Aasland <erlend@python.org>
Tue, 8 Aug 2023 21:12:35 +0000 (23:12 +0200)
committerGitHub <noreply@github.com>
Tue, 8 Aug 2023 21:12:35 +0000 (21:12 +0000)
Extract helper methods for formatting the signature and parameter
sections, and clean up the remaining function body.

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
Tools/clinic/clinic.py

index 3b26a706bafd32c30235d09b0d1abbbf7227d023..16f31717080e1f2f3281414cd743bd2409a2c8e2 100755 (executable)
@@ -5506,23 +5506,11 @@ class DSLParser:
 
         self.docstring_append(self.function, line)
 
-    def format_docstring(self) -> str:
-        f = self.function
-        assert f is not None
-
-        new_or_init = f.kind.new_or_init
-        if new_or_init and not f.docstring:
-            # don't render a docstring at all, no signature, nothing.
-            return f.docstring
-
+    def format_docstring_signature(
+        self, f: Function, parameters: list[Parameter]
+    ) -> str:
         text, add, output = _text_accumulator()
-        parameters = f.render_parameters
-
-        ##
-        ## docstring first line
-        ##
-
-        if new_or_init:
+        if f.kind.new_or_init:
             # classes get *just* the name of the class
             # not __new__, not __init__, and not module.classname
             assert f.cls
@@ -5685,35 +5673,39 @@ class DSLParser:
         if not f.docstring_only:
             add("\n" + sig_end_marker + "\n")
 
-        docstring_first_line = output()
+        signature_line = output()
 
         # now fix up the places where the brackets look wrong
-        docstring_first_line = docstring_first_line.replace(', ]', ',] ')
+        return signature_line.replace(', ]', ',] ')
 
-        # okay.  now we're officially building the "parameters" section.
-        # create substitution text for {parameters}
+    @staticmethod
+    def format_docstring_parameters(params: list[Parameter]) -> str:
+        """Create substitution text for {parameters}"""
+        text, add, output = _text_accumulator()
         spacer_line = False
-        for p in parameters:
-            if not p.docstring.strip():
+        for param in params:
+            docstring = param.docstring.strip()
+            if not docstring:
                 continue
             if spacer_line:
                 add('\n')
             else:
                 spacer_line = True
             add("  ")
-            add(p.name)
+            add(param.name)
             add('\n')
-            add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), "    "))
-        parameters_output = output()
-        if parameters_output:
-            parameters_output += '\n'
-
-        ##
-        ## docstring body
-        ##
+            stripped = rstrip_lines(docstring)
+            add(textwrap.indent(stripped, "    "))
+        if text:
+            add('\n')
+        return output()
 
-        docstring = f.docstring.rstrip()
-        lines = [line.rstrip() for line in docstring.split('\n')]
+    def format_docstring(self) -> str:
+        assert self.function is not None
+        f = self.function
+        if f.kind.new_or_init and not f.docstring:
+            # don't render a docstring at all, no signature, nothing.
+            return f.docstring
 
         # Enforce the summary line!
         # The first line of a docstring should be a summary of the function.
@@ -5727,6 +5719,7 @@ class DSLParser:
         # Guido said Clinic should enforce this:
         # http://mail.python.org/pipermail/python-dev/2013-June/127110.html
 
+        lines = f.docstring.split('\n')
         if len(lines) >= 2:
             if lines[1]:
                 fail(f"Docstring for {f.full_name!r} does not have a summary line!\n"
@@ -5738,26 +5731,23 @@ class DSLParser:
             # between it and the {parameters} we're about to add.
             lines.append('')
 
-        parameters_marker_count = len(docstring.split('{parameters}')) - 1
+        parameters_marker_count = len(f.docstring.split('{parameters}')) - 1
         if parameters_marker_count > 1:
             fail('You may not specify {parameters} more than once in a docstring!')
 
+        # insert signature at front and params after the summary line
         if not parameters_marker_count:
-            # insert after summary line
             lines.insert(2, '{parameters}')
+        lines.insert(0, '{signature}')
 
-        # insert at front of docstring
-        lines.insert(0, docstring_first_line)
-
+        # finalize docstring
+        params = f.render_parameters
+        parameters = self.format_docstring_parameters(params)
+        signature = self.format_docstring_signature(f, params)
         docstring = "\n".join(lines)
-
-        add(docstring)
-        docstring = output()
-
-        docstring = linear_format(docstring, parameters=parameters_output)
-        docstring = docstring.rstrip()
-
-        return docstring
+        return linear_format(docstring,
+                             signature=signature,
+                             parameters=parameters).rstrip()
 
     def do_post_block_processing_cleanup(self, lineno: int) -> None:
         """