From 258ca48034184bd9839fcccbd4ff362da94baf27 Mon Sep 17 00:00:00 2001 From: Henri Holopainen Date: Thu, 19 Oct 2023 14:26:36 +0300 Subject: [PATCH 1/7] Fix test behaviour --- tests/data/cases/preview_long_strings__regression.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/data/cases/preview_long_strings__regression.py b/tests/data/cases/preview_long_strings__regression.py index 40d5e745cc8..436157f4e05 100644 --- a/tests/data/cases/preview_long_strings__regression.py +++ b/tests/data/cases/preview_long_strings__regression.py @@ -210,8 +210,8 @@ def foo(): 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 ) @@ -834,7 +834,7 @@ def foo(): 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 From f9130363e07aca166a760ba71e6f766b04012437 Mon Sep 17 00:00:00 2001 From: Henri Holopainen Date: Thu, 19 Oct 2023 14:27:01 +0300 Subject: [PATCH 2/7] Add new test cases --- tests/data/cases/preview_multiline_strings.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/data/cases/preview_multiline_strings.py b/tests/data/cases/preview_multiline_strings.py index dec4ef2e548..3ff643610b7 100644 --- a/tests/data/cases/preview_multiline_strings.py +++ b/tests/data/cases/preview_multiline_strings.py @@ -157,6 +157,24 @@ def dastardly_default_value( `--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""", @@ -357,3 +375,13 @@ def dastardly_default_value( 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 From 4848d156ab67779d018fc434a7b60202725ef323 Mon Sep 17 00:00:00 2001 From: Henri Holopainen Date: Thu, 19 Oct 2023 14:29:32 +0300 Subject: [PATCH 3/7] Skip merging strings that have inline comments --- src/black/trans.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/black/trans.py b/src/black/trans.py index a2bff7f227a..a3f6467cc9e 100644 --- a/src/black/trans.py +++ b/src/black/trans.py @@ -390,7 +390,19 @@ def do_match(self, line: Line) -> TMatchResult: 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. From ffde64d7f1d3c147a7eae079aa566707c80c33d8 Mon Sep 17 00:00:00 2001 From: Henri Holopainen Date: Thu, 19 Oct 2023 14:30:47 +0300 Subject: [PATCH 4/7] Don't merge lines with multiline strings with inline comments --- src/black/linegen.py | 1 + src/black/lines.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/black/linegen.py b/src/black/linegen.py index d12ca39d037..2bfe587fa0e 100644 --- a/src/black/linegen.py +++ b/src/black/linegen.py @@ -587,6 +587,7 @@ def transform_line( 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: diff --git a/src/black/lines.py b/src/black/lines.py index 48fde888208..6acc95e7a7e 100644 --- a/src/black/lines.py +++ b/src/black/lines.py @@ -239,6 +239,21 @@ def contains_standalone_comments(self, depth_limit: int = sys.maxsize) -> bool: 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: From 707b2148d4456fc8817255bbce2c0cdf3c106d0c Mon Sep 17 00:00:00 2001 From: Henri Holopainen Date: Thu, 19 Oct 2023 14:36:22 +0300 Subject: [PATCH 5/7] Changelog entry --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 2a50e456550..3bb47b36136 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,7 +12,7 @@ ### Preview style - +- Fix merging implicit multiline strings that have inline comments (#3952) ### Configuration From 8d2b879b788804cda92245c9abea26fdd0d5f145 Mon Sep 17 00:00:00 2001 From: Henri Holopainen Date: Thu, 19 Oct 2023 15:01:01 +0300 Subject: [PATCH 6/7] Document implicit multiline string merging rules --- docs/the_black_code_style/future_style.md | 64 +++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/docs/the_black_code_style/future_style.md b/docs/the_black_code_style/future_style.md index 861bb64bff4..367ff98537c 100644 --- a/docs/the_black_code_style/future_style.md +++ b/docs/the_black_code_style/future_style.md @@ -160,3 +160,67 @@ MULTILINE = """ 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 +) +``` From 74d46c888d16832f017849706c76504fac3d4c1c Mon Sep 17 00:00:00 2001 From: Henri Holopainen Date: Thu, 19 Oct 2023 15:03:35 +0300 Subject: [PATCH 7/7] Fix PR number --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 3bb47b36136..79b5c6034e8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,7 +12,7 @@ ### Preview style -- Fix merging implicit multiline strings that have inline comments (#3952) +- Fix merging implicit multiline strings that have inline comments (#3956) ### Configuration