Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 20d8ccb

Browse files
Put closing quote on a separate line if docstring is too long (psf#3044)
Fixes psf#1632 Co-authored-by: Felix Hildén <[email protected]>
1 parent 62c2b16 commit 20d8ccb

6 files changed

Lines changed: 158 additions & 2 deletions

File tree

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
<!-- Changes that affect Black's preview style -->
1919

20+
- Fixed bug where docstrings with triple quotes could exceed max line length (#3044)
2021
- Remove redundant parentheses around awaited objects (#2991)
2122
- Parentheses around return annotations are now managed (#2990)
2223
- Remove unnecessary parentheses from `with` statements (#2926)

src/black/linegen.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,9 +305,9 @@ def visit_STRING(self, leaf: Leaf) -> Iterator[Line]:
305305
quote_len = 1 if docstring[1] != quote_char else 3
306306
docstring = docstring[quote_len:-quote_len]
307307
docstring_started_empty = not docstring
308+
indent = " " * 4 * self.current_line.depth
308309

309310
if is_multiline_string(leaf):
310-
indent = " " * 4 * self.current_line.depth
311311
docstring = fix_docstring(docstring, indent)
312312
else:
313313
docstring = docstring.strip()
@@ -329,7 +329,29 @@ def visit_STRING(self, leaf: Leaf) -> Iterator[Line]:
329329

330330
# We could enforce triple quotes at this point.
331331
quote = quote_char * quote_len
332-
leaf.value = prefix + quote + docstring + quote
332+
333+
if Preview.long_docstring_quotes_on_newline in self.mode:
334+
# We need to find the length of the last line of the docstring
335+
# to find if we can add the closing quotes to the line without
336+
# exceeding the maximum line length.
337+
# If docstring is one line, then we need to add the length
338+
# of the indent, prefix, and starting quotes. Ending quote are
339+
# handled later
340+
lines = docstring.splitlines()
341+
last_line_length = len(lines[-1]) if docstring else 0
342+
343+
if len(lines) == 1:
344+
last_line_length += len(indent) + len(prefix) + quote_len
345+
346+
# If adding closing quotes would cause the last line to exceed
347+
# the maximum line length then put a line break before the
348+
# closing quotes
349+
if last_line_length + quote_len > self.mode.line_length:
350+
leaf.value = prefix + quote + docstring + "\n" + indent + quote
351+
else:
352+
leaf.value = prefix + quote + docstring + quote
353+
else:
354+
leaf.value = prefix + quote + docstring + quote
333355

334356
yield from self.visit_default(leaf)
335357

src/black/mode.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ class Preview(Enum):
147147
remove_redundant_parens = auto()
148148
one_element_subscript = auto()
149149
annotation_parens = auto()
150+
long_docstring_quotes_on_newline = auto()
150151

151152

152153
class Deprecated(UserWarning):

tests/data/docstring.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,27 @@ def my_god_its_full_of_stars_2():
188188
"I'm sorry Dave "
189189

190190

191+
def docstring_almost_at_line_limit():
192+
"""long docstring................................................................."""
193+
194+
195+
def docstring_almost_at_line_limit2():
196+
"""long docstring.................................................................
197+
198+
..................................................................................
199+
"""
200+
201+
202+
def docstring_at_line_limit():
203+
"""long docstring................................................................"""
204+
205+
206+
def multiline_docstring_at_line_limit():
207+
"""first line-----------------------------------------------------------------------
208+
209+
second line----------------------------------------------------------------------"""
210+
211+
191212
# output
192213

193214
class MyClass:
@@ -375,3 +396,24 @@ def my_god_its_full_of_stars_1():
375396
# the space below is actually a \u2001, removed in output
376397
def my_god_its_full_of_stars_2():
377398
"I'm sorry Dave"
399+
400+
401+
def docstring_almost_at_line_limit():
402+
"""long docstring................................................................."""
403+
404+
405+
def docstring_almost_at_line_limit2():
406+
"""long docstring.................................................................
407+
408+
..................................................................................
409+
"""
410+
411+
412+
def docstring_at_line_limit():
413+
"""long docstring................................................................"""
414+
415+
416+
def multiline_docstring_at_line_limit():
417+
"""first line-----------------------------------------------------------------------
418+
419+
second line----------------------------------------------------------------------"""

tests/data/docstring_preview.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
def docstring_almost_at_line_limit():
2+
"""long docstring.................................................................
3+
"""
4+
5+
6+
def docstring_almost_at_line_limit_with_prefix():
7+
f"""long docstring................................................................
8+
"""
9+
10+
11+
def mulitline_docstring_almost_at_line_limit():
12+
"""long docstring.................................................................
13+
14+
..................................................................................
15+
"""
16+
17+
18+
def mulitline_docstring_almost_at_line_limit_with_prefix():
19+
f"""long docstring................................................................
20+
21+
..................................................................................
22+
"""
23+
24+
25+
def docstring_at_line_limit():
26+
"""long docstring................................................................"""
27+
28+
29+
def docstring_at_line_limit_with_prefix():
30+
f"""long docstring..............................................................."""
31+
32+
33+
def multiline_docstring_at_line_limit():
34+
"""first line-----------------------------------------------------------------------
35+
36+
second line----------------------------------------------------------------------"""
37+
38+
39+
def multiline_docstring_at_line_limit_with_prefix():
40+
f"""first line----------------------------------------------------------------------
41+
42+
second line----------------------------------------------------------------------"""
43+
44+
45+
# output
46+
47+
48+
def docstring_almost_at_line_limit():
49+
"""long docstring.................................................................
50+
"""
51+
52+
53+
def docstring_almost_at_line_limit_with_prefix():
54+
f"""long docstring................................................................
55+
"""
56+
57+
58+
def mulitline_docstring_almost_at_line_limit():
59+
"""long docstring.................................................................
60+
61+
..................................................................................
62+
"""
63+
64+
65+
def mulitline_docstring_almost_at_line_limit_with_prefix():
66+
f"""long docstring................................................................
67+
68+
..................................................................................
69+
"""
70+
71+
72+
def docstring_at_line_limit():
73+
"""long docstring................................................................"""
74+
75+
76+
def docstring_at_line_limit_with_prefix():
77+
f"""long docstring..............................................................."""
78+
79+
80+
def multiline_docstring_at_line_limit():
81+
"""first line-----------------------------------------------------------------------
82+
83+
second line----------------------------------------------------------------------"""
84+
85+
86+
def multiline_docstring_at_line_limit_with_prefix():
87+
f"""first line----------------------------------------------------------------------
88+
89+
second line----------------------------------------------------------------------"""

tests/test_format.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
"one_element_subscript",
9292
"remove_await_parens",
9393
"return_annotation_brackets",
94+
"docstring_preview",
9495
]
9596

9697
SOURCES: List[str] = [

0 commit comments

Comments
 (0)