Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-104683: Argument Clinic: Refactor and simplify 'add docstring' states #107550

Merged
merged 3 commits into from
Aug 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions Lib/test/test_clinic.py
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,28 @@ def test_function_docstring(self):
Path to be examined
""")

def test_docstring_trailing_whitespace(self):
function = self.parse_function(
"module t\n"
"t.s\n"
" a: object\n"
" Param docstring with trailing whitespace \n"
"Func docstring summary with trailing whitespace \n"
" \n"
"Func docstring body with trailing whitespace \n"
)
self.checkDocstring(function, """
s($module, /, a)
--

Func docstring summary with trailing whitespace

a
Param docstring with trailing whitespace

Func docstring body with trailing whitespace
""")

def test_explicit_parameters_in_docstring(self):
function = self.parse_function(dedent("""
module foo
Expand Down
55 changes: 23 additions & 32 deletions Tools/clinic/clinic.py
Original file line number Diff line number Diff line change
Expand Up @@ -4617,15 +4617,21 @@ def parse(self, block: Block) -> None:
fail("'preserve' only works for blocks that don't produce any output!")
block.output = self.saved_output

@staticmethod
def valid_line(line: str) -> bool:
def in_docstring(self) -> bool:
"""Return true if we are processing a docstring."""
return self.state in {
self.state_parameter_docstring,
self.state_function_docstring,
}

def valid_line(self, line: str) -> bool:
# ignore comment-only lines
if line.lstrip().startswith('#'):
return False

# Ignore empty lines too
# (but not in docstring sections!)
if not line.strip():
if not self.in_docstring() and not line.strip():
return False

return True
Expand Down Expand Up @@ -5262,12 +5268,20 @@ def state_parameter_docstring_start(self, line: str) -> None:
assert self.indent.depth == 3
return self.next(self.state_parameter_docstring, line)

def docstring_append(self, obj: Function | Parameter, line: str) -> None:
"""Add a rstripped line to the current docstring."""
docstring = obj.docstring
if docstring:
docstring += "\n"
if stripped := line.rstrip():
docstring += self.indent.dedent(stripped)
obj.docstring = docstring

# every line of the docstring must start with at least F spaces,
# where F > P.
# these F spaces will be stripped.
def state_parameter_docstring(self, line: str) -> None:
stripped = line.strip()
if stripped.startswith('#'):
if not self.valid_line(line):
return

indent = self.indent.measure(line)
Expand All @@ -5281,16 +5295,8 @@ def state_parameter_docstring(self, line: str) -> None:
return self.next(self.state_function_docstring, line)

assert self.function and self.function.parameters
last_parameter = next(reversed(list(self.function.parameters.values())))

new_docstring = last_parameter.docstring

if new_docstring:
new_docstring += '\n'
if stripped:
new_docstring += self.indent.dedent(line)

last_parameter.docstring = new_docstring
last_param = next(reversed(self.function.parameters.values()))
self.docstring_append(last_param, line)

# the final stanza of the DSL is the docstring.
def state_function_docstring(self, line: str) -> None:
Expand All @@ -5299,19 +5305,10 @@ def state_function_docstring(self, line: str) -> None:
if self.group:
fail("Function " + self.function.name + " has a ] without a matching [.")

stripped = line.strip()
if stripped.startswith('#'):
if not self.valid_line(line):
return

new_docstring = self.function.docstring
if new_docstring:
new_docstring += "\n"
if stripped:
line = self.indent.dedent(line).rstrip()
else:
line = ''
new_docstring += line
self.function.docstring = new_docstring
self.docstring_append(self.function, line)

def format_docstring(self) -> str:
f = self.function
Expand Down Expand Up @@ -5580,12 +5577,6 @@ def do_post_block_processing_cleanup(self) -> None:
if no_parameter_after_star:
fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.")

# remove trailing whitespace from all parameter docstrings
for name, value in self.function.parameters.items():
if not value:
continue
value.docstring = value.docstring.rstrip()
erlend-aasland marked this conversation as resolved.
Show resolved Hide resolved

self.function.docstring = self.format_docstring()


Expand Down
Loading