### Preview style
-<!-- Changes that affect Black's preview style -->
+- Fix merging implicit multiline strings that have inline comments (#3956)
### Configuration
foobar
""".replace("\n", "")
```
+
+Implicit multiline strings are special, because they can have inline comments. Strings
+without comments are merged, for example
+
+```python
+s = (
+ "An "
+ "implicit "
+ "multiline "
+ "string"
+)
+```
+
+becomes
+
+```python
+s = "An implicit multiline string"
+```
+
+A comment on any line of the string (or between two string lines) will block the
+merging, so
+
+```python
+s = (
+ "An " # Important comment concerning just this line
+ "implicit "
+ "multiline "
+ "string"
+)
+```
+
+and
+
+```python
+s = (
+ "An "
+ "implicit "
+ # Comment in between
+ "multiline "
+ "string"
+)
+```
+
+will not be merged. Having the comment after or before the string lines (but still
+inside the parens) will merge the string. For example
+
+```python
+s = ( # Top comment
+ "An "
+ "implicit "
+ "multiline "
+ "string"
+ # Bottom comment
+)
+```
+
+becomes
+
+```python
+s = ( # Top comment
+ "An implicit multiline string"
+ # Bottom comment
+)
+```
or line.contains_unsplittable_type_ignore()
)
and not (line.inside_brackets and line.contains_standalone_comments())
+ and not line.contains_implicit_multiline_string_with_comments()
):
# Only apply basic string preprocessing, since lines shouldn't be split here.
if Preview.string_processing in mode:
return False
+ def contains_implicit_multiline_string_with_comments(self) -> bool:
+ """Chck if we have an implicit multiline string with comments on the line"""
+ for leaf_type, leaf_group_iterator in itertools.groupby(
+ self.leaves, lambda leaf: leaf.type
+ ):
+ if leaf_type != token.STRING:
+ continue
+ leaf_list = list(leaf_group_iterator)
+ if len(leaf_list) == 1:
+ continue
+ for leaf in leaf_list:
+ if self.comments_after(leaf):
+ return True
+ return False
+
def contains_uncollapsable_type_comments(self) -> bool:
ignored_ids = set()
try:
and is_valid_index(idx + 1)
and LL[idx + 1].type == token.STRING
):
- if not is_part_of_annotation(leaf):
+ # Let's check if the string group contains an inline comment
+ # If we have a comment inline, we don't merge the strings
+ contains_comment = False
+ i = idx
+ while is_valid_index(i):
+ if LL[i].type != token.STRING:
+ break
+ if line.comments_after(LL[i]):
+ contains_comment = True
+ break
+ i += 1
+
+ if not is_part_of_annotation(leaf) and not contains_comment:
string_indices.append(idx)
# Advance to the next non-STRING leaf.
some_tuple = ("some string", "some string" " which should be joined")
-some_commented_string = (
- "This string is long but not so long that it needs hahahah toooooo be so greatttt" # This comment gets thrown to the top.
+some_commented_string = ( # This comment stays at the top.
+ "This string is long but not so long that it needs hahahah toooooo be so greatttt"
" {} that I just can't think of any more good words to say about it at"
" allllllllllll".format("ha") # comments here are fine
)
some_tuple = ("some string", "some string which should be joined")
-some_commented_string = ( # This comment gets thrown to the top.
+some_commented_string = ( # This comment stays at the top.
"This string is long but not so long that it needs hahahah toooooo be so greatttt"
" {} that I just can't think of any more good words to say about it at"
" allllllllllll".format("ha") # comments here are fine
`--global-option` is reserved to flags like `--verbose` or `--quiet`.
"""
+this_will_become_one_line = (
+ "a"
+ "b"
+ "c"
+)
+
+this_will_stay_on_three_lines = (
+ "a" # comment
+ "b"
+ "c"
+)
+
+this_will_also_become_one_line = ( # comment
+ "a"
+ "b"
+ "c"
+)
+
# output
"""cow
say""",
Please use `--build-option` instead,
`--global-option` is reserved to flags like `--verbose` or `--quiet`.
"""
+
+this_will_become_one_line = "abc"
+
+this_will_stay_on_three_lines = (
+ "a" # comment
+ "b"
+ "c"
+)
+
+this_will_also_become_one_line = "abc" # comment