Skip to content
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
28 changes: 23 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ multi-line docstring

**PEP 257: _The closing quotes are on the same line as the opening quotes_**

For consistency this rule also gets applied to multi-line docstrings
For consistency this rule also gets applied to multi-line docstrings.

```python
# Bad
Expand Down Expand Up @@ -112,6 +112,9 @@ of a summary line just like a one-line docstring_**

Since the first line should be a phrase or summary the first character gets capitalized.

When the second line is one recurring character we consider the summary line to be a
title as used in many Sphinx documentation schemes and do not add a period.

```python
# Bad
"""My docstring"""
Expand All @@ -127,26 +130,41 @@ My docstring

"""Summary.

My docstring
"""

"""My title
===========

My docstring
"""
```

**PEP 257: _Multi-line docstrings consist of a summary line just like a one-line
docstring, followed by a blank line, followed by a more elaborate description._**

When the second line is one recurring character we consider the summary line to be a
title as used in many Sphinx documentation schemes and do not add a white line.

```python
# Bad
"""Summary. Body."""

"""Summary.
Body.
"""
Body.
"""

# Good
"""Summary.

Body.
"""
Body.
"""

"""My title
===========

My docstring
"""
```

## Development
Expand Down
19 changes: 10 additions & 9 deletions pydocstringformatter/formatting/formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,16 @@ def _treat_string(self, tokeninfo: tokenize.TokenInfo, _: int) -> str:
return tokeninfo.string[:-3] + "." + tokeninfo.string[-3:]
# Handle multi-line docstrings
else:
first_linebreak = tokeninfo.string.index("\n")
# If first linebreak is followed by another we're dealing with a summary
if tokeninfo.string[tokeninfo.string.index("\n") + 1] == "\n":
if tokeninfo.string[first_linebreak - 1] != ".":
return (
tokeninfo.string[:first_linebreak]
+ "."
+ tokeninfo.string[first_linebreak:]
)
lines = tokeninfo.string.splitlines()
# If second line is one recurring character we're dealing with a rst title
if (stripped := lines[1].lstrip()) and stripped.count(stripped[0]) == len(
stripped
):
return tokeninfo.string
# If second line is empty we're dealing with a summary
if lines[1] == "":
if lines[0][-1] != ".":
return lines[0] + ".\n" + "\n".join(lines[1:])
# TODO(#26): Handle multi-line docstrings that do not have a summary
# This is obviously dependent on whether 'pydocstringformatter' will
# start enforcing summaries :)
Expand Down
42 changes: 42 additions & 0 deletions tests/data/format/final_period/function_title_docstrings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
def func():
def inner_func():
"""Summary
==========

docstring
"""

def inner_func():
"""Summary
----------

docstring
"""

def inner_func():
"""Summary
^^^^^^^^^^

docstring
"""

def inner_func():
"""Summary
**********

docstring
"""

def inner_func():
"""Summary
^^^^^^^^^^

docstring
"""

def inner_func():
"""Summary
aaaaaaaaaa

docstring
"""
42 changes: 42 additions & 0 deletions tests/data/format/final_period/function_title_docstrings.py.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
def func():
def inner_func():
"""Summary
==========

docstring
"""

def inner_func():
"""Summary
----------

docstring
"""

def inner_func():
"""Summary
^^^^^^^^^^

docstring
"""

def inner_func():
"""Summary
**********

docstring
"""

def inner_func():
"""Summary
^^^^^^^^^^

docstring
"""

def inner_func():
"""Summary
aaaaaaaaaa

docstring
"""