gh-104683: Argument Clinic: refactor format_docstring() (#107623)

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>
This commit is contained in:
Erlend E. Aasland 2023-08-08 23:12:35 +02:00 committed by GitHub
parent 0be3743f54
commit 73507382ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

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