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

Add improved docstring processing #2885

Open
wants to merge 55 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
f263927
Add improved docstring processing
TomFryers Feb 17, 2022
be791f5
Add PR number to changelog
TomFryers Feb 17, 2022
073a55d
separate CHANGELOG section for preview style
JelleZijlstra Feb 21, 2022
52a36b5
Make fix_docstring preview parameter keyword-only
TomFryers Feb 21, 2022
3895c4d
Pretend to be in preview mode for diff-shades
TomFryers Feb 21, 2022
30e0ad3
Merge branch 'psf:main' into main
TomFryers Feb 21, 2022
0802ada
Merge remote-tracking branch 'origin/previewstyle'
TomFryers Feb 21, 2022
2541264
Revert "Pretend to be in preview mode for diff-shades"
TomFryers Feb 21, 2022
6156ea5
Merge branch 'main' of https://github.com/psf/black
TomFryers Feb 24, 2022
975767f
Blacken Black
TomFryers Feb 24, 2022
8adc896
Shorten over-long docstrings
TomFryers Feb 24, 2022
e5cdcff
Move opening quotes off own line
TomFryers Mar 2, 2022
7ed5fd2
Fix first-line indentation
TomFryers Mar 2, 2022
ebb4a32
Revert "Revert "Pretend to be in preview mode for diff-shades""
TomFryers Mar 2, 2022
a79d394
Undo temporary changes
TomFryers Mar 2, 2022
d223a97
Merge branch 'psf:main' into main
TomFryers Mar 11, 2022
ea07503
Merge remote-tracking branch 'origin/main'
TomFryers Mar 16, 2022
45a52de
Merge remote-tracking branch 'origin/main'
TomFryers Mar 25, 2022
54e8451
Merge remote-tracking branch 'origin/main'
TomFryers Mar 27, 2022
e073b63
Merge remote-tracking branch 'origin/main'
TomFryers Mar 28, 2022
76c5c13
Merge remote-tracking branch 'origin/main'
TomFryers Apr 5, 2022
06b2587
Merge branch 'main' into main
JelleZijlstra Apr 11, 2022
54976a3
Merge remote-tracking branch 'origin/main'
TomFryers Apr 22, 2022
2360449
Merge remote-tracking branch 'origin/main'
TomFryers May 5, 2022
ba84a7c
Merge remote-tracking branch 'origin/main'
TomFryers May 23, 2022
7b33820
Merge remote-tracking branch 'origin/main'
TomFryers Jun 10, 2022
8fc0430
Fix tests
TomFryers Jun 10, 2022
4b5f3c7
Fix bad single-line docstring indentation
TomFryers Jun 10, 2022
25be451
Merge remote-tracking branch 'origin/main'
TomFryers Jun 11, 2022
f51ea0a
Remove merge conflict residue
TomFryers Jun 11, 2022
b638eeb
Merge remote-tracking branch 'origin/main'
TomFryers Jul 9, 2022
5ad579a
Merge remote-tracking branch 'origin/main'
TomFryers Aug 2, 2022
08ec335
Merge remote-tracking branch 'origin/main'
TomFryers Aug 3, 2022
d72db33
Merge remote-tracking branch 'origin/main'
TomFryers Aug 17, 2022
f6d9127
Merge remote-tracking branch 'origin/main'
TomFryers Aug 30, 2022
a34724e
Blacken unblackened file
TomFryers Aug 30, 2022
0c872ce
Merge remote-tracking branch 'origin/main'
TomFryers Sep 2, 2022
b8d9c2e
Remove rogue merge marker
TomFryers Sep 2, 2022
2e71f32
Add whitespace to CHANGES.md
TomFryers Sep 2, 2022
b98a6a6
Merge remote-tracking branch 'origin/main'
TomFryers Sep 15, 2022
1595441
Merge branch 'main' into main
TomFryers Sep 26, 2022
a58d21c
Merge branch 'main' into main
TomFryers Oct 18, 2022
67cd06c
Merge branch 'main' into main
TomFryers Oct 27, 2022
3b089e3
Remove extra blank line
TomFryers Oct 27, 2022
9c6d257
Put LinesBlock docstring quotes on their own line
TomFryers Oct 27, 2022
ffaae19
Merge branch 'main' into main
TomFryers Nov 3, 2022
86d806c
Merge branch 'main' into main
TomFryers Nov 9, 2022
e5e2da6
Merge remote-tracking branch 'origin/main'
TomFryers Nov 10, 2022
9ba93f5
Use new quote style
TomFryers Nov 10, 2022
12dd417
Merge remote-tracking branch 'origin/main'
TomFryers Feb 9, 2023
34dbe7e
Fix docstring preview tests
TomFryers Feb 9, 2023
88fe1aa
Blacken Black
TomFryers Feb 9, 2023
c1f6e4a
Shorten docstring to fit in limit
TomFryers Feb 9, 2023
2f16112
Merge remote-tracking branch 'origin/main'
TomFryers Mar 31, 2024
b8c169f
Fix documentation link
TomFryers Mar 31, 2024
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
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

<!-- Changes that affect Black's style -->

- Format docstrings to have consistent quote placement (#2885)
TomFryers marked this conversation as resolved.
Show resolved Hide resolved

### _Blackd_

<!-- Changes to blackd -->
Expand Down
6 changes: 6 additions & 0 deletions docs/the_black_code_style/future_style.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,9 @@ plain strings. User-made splits are respected when they do not exceed the line l
limit. Line continuation backslashes are converted into parenthesized strings.
Unnecessary parentheses are stripped. The stability and status of this feature is
tracked in [this issue](https://github.com/psf/black/issues/2188).

### Improved docstring processing

_Black_ will ensure docstrings are formatted consistently, by removing extra blank lines
at the beginning and end of docstrings, ensuring the opening and closing quotes are on
their own lines and collapsing docstrings with a single line of text down to one line.
2 changes: 1 addition & 1 deletion src/black/linegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ def visit_STRING(self, leaf: Leaf) -> Iterator[Line]:

if is_multiline_string(leaf):
indent = " " * 4 * self.current_line.depth
docstring = fix_docstring(docstring, indent)
docstring = fix_docstring(docstring, indent, self.mode.preview)
else:
docstring = docstring.strip()

Expand Down
16 changes: 14 additions & 2 deletions src/black/strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def lines_with_leading_tabs_expanded(s: str) -> List[str]:
return lines


def fix_docstring(docstring: str, prefix: str) -> str:
def fix_docstring(docstring: str, prefix: str, preview: bool) -> str:
TomFryers marked this conversation as resolved.
Show resolved Hide resolved
# https://www.python.org/dev/peps/pep-0257/#handling-docstring-indentation
if not docstring:
return ""
Expand All @@ -81,7 +81,19 @@ def fix_docstring(docstring: str, prefix: str) -> str:
trimmed.append(prefix + stripped_line)
else:
trimmed.append("")
return "\n".join(trimmed)
if not preview:
return "\n".join(trimmed)
# Remove extra blank lines at the ends
if all(not line or line.isspace() for line in trimmed):
return ""
for end in (0, -1):
while not trimmed[end] or trimmed[end].isspace():
trimmed.pop(end)
trimmed[0] = prefix + trimmed[0].strip()
# Make single-line docstring single-lined
if len(trimmed) == 1:
return trimmed[0]
return "\n".join(("", *trimmed, prefix))


def get_string_prefix(string: str) -> str:
Expand Down
6 changes: 4 additions & 2 deletions tests/data/comments.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
#
# Has many lines. Many, many lines.
# Many, many, many lines.
"""Module docstring.
"""
Module docstring.

Possibly also many, many lines.
"""
Expand All @@ -30,7 +31,8 @@


def function(default=None):
"""Docstring comes first.
"""
Docstring comes first.

Possibly many lines.
"""
Expand Down
10 changes: 6 additions & 4 deletions tests/data/comments_non_breaking_space.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@
square = Square(4) # type: Optional[Square]

def function(a:int=42):
""" This docstring is already formatted
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you change the input section here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the same file works for the tests with --preview and without. I wanted to limit the set of test files where that differed to the two main docstring ones (docstring_no_string_normalization.py, docstring.py and their _preview counterparts). I did a similar thing to fmtonoff.py and comments.py.

a
b
"""
This docstring is already formatted
a
b
"""
#  There's a NBSP + 3 spaces before
# And 4 spaces on the next line
Expand All @@ -35,7 +36,8 @@ def function(a:int=42):


def function(a: int = 42):
"""This docstring is already formatted
"""
This docstring is already formatted
a
b
"""
Expand Down
241 changes: 241 additions & 0 deletions tests/data/docstring_no_string_normalization_preview.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
class ALonelyClass:
'''
A multiline class docstring.
'''
def AnEquallyLonelyMethod(self):
'''
A multiline method docstring'''
pass


def one_function():
'''This is a docstring with a single line of text.'''
pass


def shockingly_the_quotes_are_normalized():
'''This is a multiline docstring.
This is a multiline docstring.
This is a multiline docstring.
'''
pass


def foo():
"""This is a docstring with
some lines of text here
"""
return


def baz():
'''"This" is a string with some
embedded "quotes"'''
return


def poit():
"""
Lorem ipsum dolor sit amet.

Consectetur adipiscing elit:
- sed do eiusmod tempor incididunt ut labore
- dolore magna aliqua
- enim ad minim veniam
- quis nostrud exercitation ullamco laboris nisi
- aliquip ex ea commodo consequat
"""
pass


def under_indent():
"""
These lines are indented in a way that does not
make sense.
"""
pass


def over_indent():
"""
This has a shallow indent
- But some lines are deeper
- And the closing quote is too deep
"""
pass


def single_line():
"""But with a newline after it!

"""
pass


def this():
r"""
'hey ho'
"""


def that():
""" "hey yah" """


def and_that():
"""
"hey yah" """


def and_this():
'''
"hey yah"'''


def believe_it_or_not_this_is_in_the_py_stdlib(): '''
"hey yah"'''


def shockingly_the_quotes_are_normalized_v2():
'''
Docstring Docstring Docstring
'''
pass


def backslash_space():
'\ '


def multiline_backslash_1():
'''
hey\there\
\ '''


def multiline_backslash_2():
'''
hey there \ '''


def multiline_backslash_3():
'''
already escaped \\ '''

# output

class ALonelyClass:
'''A multiline class docstring.'''

def AnEquallyLonelyMethod(self):
'''A multiline method docstring'''
pass


def one_function():
'''This is a docstring with a single line of text.'''
pass


def shockingly_the_quotes_are_normalized():
'''
This is a multiline docstring.
This is a multiline docstring.
This is a multiline docstring.
'''
pass


def foo():
"""
This is a docstring with
some lines of text here
"""
return


def baz():
'''
"This" is a string with some
embedded "quotes"
'''
return


def poit():
"""
Lorem ipsum dolor sit amet.

Consectetur adipiscing elit:
- sed do eiusmod tempor incididunt ut labore
- dolore magna aliqua
- enim ad minim veniam
- quis nostrud exercitation ullamco laboris nisi
- aliquip ex ea commodo consequat
"""
pass


def under_indent():
"""
These lines are indented in a way that does not
make sense.
"""
pass


def over_indent():
"""
This has a shallow indent
- But some lines are deeper
- And the closing quote is too deep
"""
pass


def single_line():
"""But with a newline after it!"""
pass


def this():
r"""'hey ho'"""


def that():
""" "hey yah" """


def and_that():
""" "hey yah" """


def and_this():
'''"hey yah"'''


def believe_it_or_not_this_is_in_the_py_stdlib():
'''"hey yah"'''


def shockingly_the_quotes_are_normalized_v2():
'''Docstring Docstring Docstring'''
pass


def backslash_space():
'\ '


def multiline_backslash_1():
'''
hey\there\
\ '''


def multiline_backslash_2():
'''hey there \ '''


def multiline_backslash_3():
'''already escaped \\'''
Loading