From df60609cda10596ac1343937c0039a8ca4660327 Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Mon, 25 Apr 2022 12:08:36 +0300 Subject: [PATCH 01/21] black will remove newlines between `def` statement and its function content --- src/black/lines.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/black/lines.py b/src/black/lines.py index e455a507539..2dd3ee92fe0 100644 --- a/src/black/lines.py +++ b/src/black/lines.py @@ -513,6 +513,12 @@ def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]: ): return before, 1 + if ( + self.previous_line + and self.previous_line.is_def + and depth == self.previous_line.depth + 1 + ): + return 0, 0 return before, 0 def _maybe_empty_lines_for_class_or_def( From 13f2aaf9f55b87cb8080b4c6bddc0b8a306cc756 Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Mon, 25 Apr 2022 12:08:45 +0300 Subject: [PATCH 02/21] Test the new ability --- tests/data/newline_after_def.py | 8 ++++++++ tests/test_black.py | 1 - tests/test_format.py | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 tests/data/newline_after_def.py diff --git a/tests/data/newline_after_def.py b/tests/data/newline_after_def.py new file mode 100644 index 00000000000..85381b43821 --- /dev/null +++ b/tests/data/newline_after_def.py @@ -0,0 +1,8 @@ +def foo(): + + print("The newline above me should be deleted!") + +# output + +def foo(): + print("The newline above me should be deleted!") diff --git a/tests/test_black.py b/tests/test_black.py index f6663fa5797..aad6b02d680 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -1451,7 +1451,6 @@ def test_newline_comment_interaction(self) -> None: black.assert_stable(source, output, mode=DEFAULT_MODE) def test_bpo_2142_workaround(self) -> None: - # https://bugs.python.org/issue2142 source, _ = read_data("missing_final_newline.py") diff --git a/tests/test_format.py b/tests/test_format.py index 1916146e84d..256b2c1352e 100644 --- a/tests/test_format.py +++ b/tests/test_format.py @@ -50,6 +50,7 @@ "function2", "function_trailing_comma", "import_spacing", + "newline_after_def", "power_op_spacing", "remove_parens", "slices", From 8d6c37345a58be00b96691541e1b7135c59abf38 Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Mon, 25 Apr 2022 12:19:39 +0300 Subject: [PATCH 03/21] Add change to CHANGES.md --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 566077b1dbc..19b4eef9a8c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,7 @@ - Fix unstable formatting involving `# fmt: skip` comments without internal spaces (#2970) +- trailing newlines are removed right after `def` statement (#3035) ### Preview style From b991571291d77a27df1e1e06c5536016df09028a Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Mon, 25 Apr 2022 12:22:52 +0300 Subject: [PATCH 04/21] Added a few test cases --- .../{newline_after_def.py => newline_after_def1.py} | 0 tests/data/newline_after_def2.py | 10 ++++++++++ tests/data/newline_after_def3.py | 12 ++++++++++++ tests/test_format.py | 4 +++- 4 files changed, 25 insertions(+), 1 deletion(-) rename tests/data/{newline_after_def.py => newline_after_def1.py} (100%) create mode 100644 tests/data/newline_after_def2.py create mode 100644 tests/data/newline_after_def3.py diff --git a/tests/data/newline_after_def.py b/tests/data/newline_after_def1.py similarity index 100% rename from tests/data/newline_after_def.py rename to tests/data/newline_after_def1.py diff --git a/tests/data/newline_after_def2.py b/tests/data/newline_after_def2.py new file mode 100644 index 00000000000..2d586583d2a --- /dev/null +++ b/tests/data/newline_after_def2.py @@ -0,0 +1,10 @@ +def foo(): + + + + print("All the newlines above me should be deleted!") + +# output + +def foo(): + print("All the newlines above me should be deleted!") diff --git a/tests/data/newline_after_def3.py b/tests/data/newline_after_def3.py new file mode 100644 index 00000000000..92b7480abec --- /dev/null +++ b/tests/data/newline_after_def3.py @@ -0,0 +1,12 @@ +def f(): + + print("No newline above me!") + + print("There is a newline above me, and that's OK!") + +# output + +def f(): + print("No newline above me!") + + print("There is a newline above me, and that's OK!") diff --git a/tests/test_format.py b/tests/test_format.py index 256b2c1352e..10360aa24f4 100644 --- a/tests/test_format.py +++ b/tests/test_format.py @@ -50,7 +50,9 @@ "function2", "function_trailing_comma", "import_spacing", - "newline_after_def", + "newline_after_def1", + "newline_after_def2", + "newline_after_def3", "power_op_spacing", "remove_parens", "slices", From 549a094f6f02776b28b362bc87540e5ea41f5a0d Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Mon, 25 Apr 2022 12:50:46 +0300 Subject: [PATCH 05/21] Added more tests --- tests/data/newline_after_def4.py | 12 ++++++++++++ tests/data/newline_after_def5.py | 10 ++++++++++ tests/test_format.py | 2 ++ 3 files changed, 24 insertions(+) create mode 100644 tests/data/newline_after_def4.py create mode 100644 tests/data/newline_after_def5.py diff --git a/tests/data/newline_after_def4.py b/tests/data/newline_after_def4.py new file mode 100644 index 00000000000..4d6717261c8 --- /dev/null +++ b/tests/data/newline_after_def4.py @@ -0,0 +1,12 @@ +def foo(): + + # There is a comment here + + print("The newline above me should not be deleted!") + +# output + +def foo(): + # There is a comment here + + print("The newline above me should not be deleted!") diff --git a/tests/data/newline_after_def5.py b/tests/data/newline_after_def5.py new file mode 100644 index 00000000000..d6c383ee36a --- /dev/null +++ b/tests/data/newline_after_def5.py @@ -0,0 +1,10 @@ +class Foo: + def bar(self): + + print("The newline above me should be deleted!") + +# output + +class Foo: + def bar(self): + print("The newline above me should be deleted!") diff --git a/tests/test_format.py b/tests/test_format.py index 10360aa24f4..87d5a755730 100644 --- a/tests/test_format.py +++ b/tests/test_format.py @@ -53,6 +53,8 @@ "newline_after_def1", "newline_after_def2", "newline_after_def3", + "newline_after_def4", + "newline_after_def5", "power_op_spacing", "remove_parens", "slices", From c30a951324720ea6e0e49bb02befcea18396ce2f Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Mon, 25 Apr 2022 16:24:14 +0300 Subject: [PATCH 06/21] Update CHANGES.md according to suggestion Co-authored-by: Jelle Zijlstra --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 19b4eef9a8c..6ad0ae56324 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,7 +12,7 @@ - Fix unstable formatting involving `# fmt: skip` comments without internal spaces (#2970) -- trailing newlines are removed right after `def` statement (#3035) +- Remove trailing newlines after `def` lines (#3035) ### Preview style From 17516d76b2dc2fa7845378ace80b64d1d48bdf2e Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Mon, 25 Apr 2022 16:34:00 +0300 Subject: [PATCH 07/21] remove trailing newline in `def` statement is now a preview ability --- CHANGES.md | 2 +- src/black/lines.py | 3 ++- src/black/mode.py | 1 + tests/test_format.py | 10 +++++----- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 6ad0ae56324..bf5614fd65d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,7 +12,6 @@ - Fix unstable formatting involving `# fmt: skip` comments without internal spaces (#2970) -- Remove trailing newlines after `def` lines (#3035) ### Preview style @@ -21,6 +20,7 @@ - Remove redundant parentheses around awaited objects (#2991) - Parentheses around return annotations are now managed (#2990) - Remove unnecessary parentheses from `with` statements (#2926) +- Remove trailing newlines after `def` lines (#3035) ### _Blackd_ diff --git a/src/black/lines.py b/src/black/lines.py index 2dd3ee92fe0..98552519d3e 100644 --- a/src/black/lines.py +++ b/src/black/lines.py @@ -514,7 +514,8 @@ def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]: return before, 1 if ( - self.previous_line + Preview.remove_def_trailing_newline in current_line.mode + and self.previous_line and self.previous_line.is_def and depth == self.previous_line.depth + 1 ): diff --git a/src/black/mode.py b/src/black/mode.py index 6bd4ce14421..e116bd105e1 100644 --- a/src/black/mode.py +++ b/src/black/mode.py @@ -147,6 +147,7 @@ class Preview(Enum): remove_redundant_parens = auto() one_element_subscript = auto() annotation_parens = auto() + remove_def_trailing_newline = auto() class Deprecated(UserWarning): diff --git a/tests/test_format.py b/tests/test_format.py index 87d5a755730..2390f60c1eb 100644 --- a/tests/test_format.py +++ b/tests/test_format.py @@ -50,11 +50,6 @@ "function2", "function_trailing_comma", "import_spacing", - "newline_after_def1", - "newline_after_def2", - "newline_after_def3", - "newline_after_def4", - "newline_after_def5", "power_op_spacing", "remove_parens", "slices", @@ -87,6 +82,11 @@ "cantfit", "comments7", "comments8", + "newline_after_def1", + "newline_after_def2", + "newline_after_def3", + "newline_after_def4", + "newline_after_def5", "long_strings", "long_strings__edge_case", "long_strings__regression", From bb97364d4d1683eaf214557c3aa7d069063b0182 Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Mon, 25 Apr 2022 16:37:12 +0300 Subject: [PATCH 08/21] Add myself to AUTHORS.md since it's my forth PR in *Black* --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 8aa6263313e..faa2b05840f 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -148,6 +148,7 @@ Multiple contributions by: - [Rishikesh Jha](mailto:rishijha424@gmail.com) - [Rupert Bedford](mailto:rupert@rupertb.com) - Russell Davis +- [Sagi Shadur](mailto:saroad2@gmail.com) - [RĂ©mi Verschelde](mailto:rverschelde@gmail.com) - [Sami Salonen](mailto:sakki@iki.fi) - [Samuel Cormier-Iijima](mailto:samuel@cormier-iijima.com) From 700c51d4de024caf669559b551ddb09aa851db4c Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Wed, 18 May 2022 22:14:50 +0300 Subject: [PATCH 09/21] Move new test cases to preview directory --- tests/data/{ => preview}/newline_after_def1.py | 0 tests/data/{ => preview}/newline_after_def2.py | 0 tests/data/{ => preview}/newline_after_def3.py | 0 tests/data/{ => preview}/newline_after_def4.py | 0 tests/data/{ => preview}/newline_after_def5.py | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename tests/data/{ => preview}/newline_after_def1.py (100%) rename tests/data/{ => preview}/newline_after_def2.py (100%) rename tests/data/{ => preview}/newline_after_def3.py (100%) rename tests/data/{ => preview}/newline_after_def4.py (100%) rename tests/data/{ => preview}/newline_after_def5.py (100%) diff --git a/tests/data/newline_after_def1.py b/tests/data/preview/newline_after_def1.py similarity index 100% rename from tests/data/newline_after_def1.py rename to tests/data/preview/newline_after_def1.py diff --git a/tests/data/newline_after_def2.py b/tests/data/preview/newline_after_def2.py similarity index 100% rename from tests/data/newline_after_def2.py rename to tests/data/preview/newline_after_def2.py diff --git a/tests/data/newline_after_def3.py b/tests/data/preview/newline_after_def3.py similarity index 100% rename from tests/data/newline_after_def3.py rename to tests/data/preview/newline_after_def3.py diff --git a/tests/data/newline_after_def4.py b/tests/data/preview/newline_after_def4.py similarity index 100% rename from tests/data/newline_after_def4.py rename to tests/data/preview/newline_after_def4.py diff --git a/tests/data/newline_after_def5.py b/tests/data/preview/newline_after_def5.py similarity index 100% rename from tests/data/newline_after_def5.py rename to tests/data/preview/newline_after_def5.py From fd1da5cf1f0656cb32b6437ea0ba55ecad3536af Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Wed, 18 May 2022 22:23:33 +0300 Subject: [PATCH 10/21] *Black* now removes newlines after EVERY open block statement --- src/black/lines.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/black/lines.py b/src/black/lines.py index 98552519d3e..6cb88d8242c 100644 --- a/src/black/lines.py +++ b/src/black/lines.py @@ -168,6 +168,13 @@ def is_triple_quoted_string(self) -> bool: and self.leaves[0].value.startswith(('"""', "'''")) ) + @property + def opens_block(self) -> bool: + """Does this line open a new level of indentation.""" + if len(self.leaves) == 0: + return False + return self.leaves[-1].type == token.COLON + def contains_standalone_comments(self, depth_limit: int = sys.maxsize) -> bool: """If so, needs to be split before emitting.""" for leaf in self.leaves: @@ -516,8 +523,7 @@ def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]: if ( Preview.remove_def_trailing_newline in current_line.mode and self.previous_line - and self.previous_line.is_def - and depth == self.previous_line.depth + 1 + and self.previous_line.opens_block ): return 0, 0 return before, 0 From c845c0c796e0bdd46f632328d747e106976d5a19 Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Wed, 18 May 2022 22:25:09 +0300 Subject: [PATCH 11/21] Add unit tests for removing newlines --- tests/data/preview/newline_after_for1.py | 8 ++++++++ tests/data/preview/newline_after_for2.py | 10 ++++++++++ tests/data/preview/newline_after_for3.py | 11 +++++++++++ tests/data/preview/newline_after_if1.py | 11 +++++++++++ tests/data/preview/newline_after_if2.py | 14 ++++++++++++++ tests/data/preview/newline_after_if3.py | 14 ++++++++++++++ tests/data/preview/newline_after_while1.py | 8 ++++++++ tests/data/preview/newline_after_while2.py | 10 ++++++++++ tests/data/preview/newline_after_while3.py | 11 +++++++++++ tests/data/preview/newline_after_with1.py | 8 ++++++++ tests/data/preview/newline_after_with2.py | 10 ++++++++++ tests/data/preview/newline_after_with3.py | 11 +++++++++++ 12 files changed, 126 insertions(+) create mode 100644 tests/data/preview/newline_after_for1.py create mode 100644 tests/data/preview/newline_after_for2.py create mode 100644 tests/data/preview/newline_after_for3.py create mode 100644 tests/data/preview/newline_after_if1.py create mode 100644 tests/data/preview/newline_after_if2.py create mode 100644 tests/data/preview/newline_after_if3.py create mode 100644 tests/data/preview/newline_after_while1.py create mode 100644 tests/data/preview/newline_after_while2.py create mode 100644 tests/data/preview/newline_after_while3.py create mode 100644 tests/data/preview/newline_after_with1.py create mode 100644 tests/data/preview/newline_after_with2.py create mode 100644 tests/data/preview/newline_after_with3.py diff --git a/tests/data/preview/newline_after_for1.py b/tests/data/preview/newline_after_for1.py new file mode 100644 index 00000000000..51cb3fa541c --- /dev/null +++ b/tests/data/preview/newline_after_for1.py @@ -0,0 +1,8 @@ +for i in range(5): + + print(f"{i}) The line above me should be removed!") + +# output + +for i in range(5): + print(f"{i}) The line above me should be removed!") \ No newline at end of file diff --git a/tests/data/preview/newline_after_for2.py b/tests/data/preview/newline_after_for2.py new file mode 100644 index 00000000000..d226e25782e --- /dev/null +++ b/tests/data/preview/newline_after_for2.py @@ -0,0 +1,10 @@ +for i in range(5): + + + + print(f"{i}) The lines above me should be removed!") + +# output + +for i in range(5): + print(f"{i}) The lines above me should be removed!") \ No newline at end of file diff --git a/tests/data/preview/newline_after_for3.py b/tests/data/preview/newline_after_for3.py new file mode 100644 index 00000000000..ecb32c8563d --- /dev/null +++ b/tests/data/preview/newline_after_for3.py @@ -0,0 +1,11 @@ +for i in range(5): + + for j in range(7): + + print(f"{i}) The lines above me should be removed!") + +# output + +for i in range(5): + for j in range(7): + print(f"{i}) The lines above me should be removed!") diff --git a/tests/data/preview/newline_after_if1.py b/tests/data/preview/newline_after_if1.py new file mode 100644 index 00000000000..d69f0025ee0 --- /dev/null +++ b/tests/data/preview/newline_after_if1.py @@ -0,0 +1,11 @@ +import random + +if random.randint(0, 3) == 0: + + print("The new line above me is about to be removed!") + +# output +import random + +if random.randint(0, 3) == 0: + print("The new line above me is about to be removed!") \ No newline at end of file diff --git a/tests/data/preview/newline_after_if2.py b/tests/data/preview/newline_after_if2.py new file mode 100644 index 00000000000..f34299f39fa --- /dev/null +++ b/tests/data/preview/newline_after_if2.py @@ -0,0 +1,14 @@ +import random + +if random.randint(0, 3) == 0: + + + + + print("The new lines above me is about to be removed!") + +# output +import random + +if random.randint(0, 3) == 0: + print("The new lines above me is about to be removed!") \ No newline at end of file diff --git a/tests/data/preview/newline_after_if3.py b/tests/data/preview/newline_after_if3.py new file mode 100644 index 00000000000..9db334cf03e --- /dev/null +++ b/tests/data/preview/newline_after_if3.py @@ -0,0 +1,14 @@ +import random + +if random.randint(0, 3) == 0: + + if random.uniform(0, 1) > 0.5: + + print("Two lines above me are about to be removed!") + +# output +import random + +if random.randint(0, 3) == 0: + if random.uniform(0, 1) > 0.5: + print("Two lines above me are about to be removed!") diff --git a/tests/data/preview/newline_after_while1.py b/tests/data/preview/newline_after_while1.py new file mode 100644 index 00000000000..2382aa53b8d --- /dev/null +++ b/tests/data/preview/newline_after_while1.py @@ -0,0 +1,8 @@ +while True: + + print("The newline above me should be deleted!") + +# output + +while True: + print("The newline above me should be deleted!") diff --git a/tests/data/preview/newline_after_while2.py b/tests/data/preview/newline_after_while2.py new file mode 100644 index 00000000000..4976a582ba5 --- /dev/null +++ b/tests/data/preview/newline_after_while2.py @@ -0,0 +1,10 @@ +while True: + + + + print("The newlines above me should be deleted!") + +# output + +while True: + print("The newlines above me should be deleted!") diff --git a/tests/data/preview/newline_after_while3.py b/tests/data/preview/newline_after_while3.py new file mode 100644 index 00000000000..e2e10b8e363 --- /dev/null +++ b/tests/data/preview/newline_after_while3.py @@ -0,0 +1,11 @@ +while True: + + while False: + + print("The newlines above me should be deleted!") + +# output + +while True: + while False: + print("The newlines above me should be deleted!") diff --git a/tests/data/preview/newline_after_with1.py b/tests/data/preview/newline_after_with1.py new file mode 100644 index 00000000000..cdbd9fe54e8 --- /dev/null +++ b/tests/data/preview/newline_after_with1.py @@ -0,0 +1,8 @@ +with open("/path/to/file.txt", mode="w") as file: + + file.write("The new line above me is about to be removed!") + +# output + +with open("/path/to/file.txt", mode="w") as file: + file.write("The new line above me is about to be removed!") diff --git a/tests/data/preview/newline_after_with2.py b/tests/data/preview/newline_after_with2.py new file mode 100644 index 00000000000..e0fb2f07e85 --- /dev/null +++ b/tests/data/preview/newline_after_with2.py @@ -0,0 +1,10 @@ +with open("/path/to/file.txt", mode="w") as file: + + + + file.write("The new lines above me is about to be removed!") + +# output + +with open("/path/to/file.txt", mode="w") as file: + file.write("The new lines above me is about to be removed!") diff --git a/tests/data/preview/newline_after_with3.py b/tests/data/preview/newline_after_with3.py new file mode 100644 index 00000000000..e6ff391f119 --- /dev/null +++ b/tests/data/preview/newline_after_with3.py @@ -0,0 +1,11 @@ +with open("/path/to/file.txt", mode="r") as read_file: + + with open("/path/to/output_file.txt", mode="w") as write_file: + + write_file.writelines(read_file.readlines()) + +# output + +with open("/path/to/file.txt", mode="r") as read_file: + with open("/path/to/output_file.txt", mode="w") as write_file: + write_file.writelines(read_file.readlines()) From f8bbdbb1d4d1cdfeaa2e9388b92005069ae3b69d Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Thu, 19 May 2022 09:48:42 +0300 Subject: [PATCH 12/21] Add new feature to future_style.md --- docs/the_black_code_style/future_style.md | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/docs/the_black_code_style/future_style.md b/docs/the_black_code_style/future_style.md index 2ec2c0333a5..7a3cddb4231 100644 --- a/docs/the_black_code_style/future_style.md +++ b/docs/the_black_code_style/future_style.md @@ -49,3 +49,31 @@ 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). + +### Removing trailing newlines after code block open + +Newlines are great. They help us organize our code and leave room for the coders and +reviewers to breath. However, too many newlines can make simple code gigantic and +massive. This is unnecessary in a lot of cases. In order to reduce the number of +redundant newlines, _Black_ will remove trailing newlines after code block openings. +That means that the following code: + +```python +def my_func(): + + print("The line above me will be deleted!") + + print("But the line above me won't!") +``` + +Will change to: + +```python +def my_func(): + print("The line above me will be deleted!") + + print("But the line above me won't!") +``` + +This new feature will be applied to **all _Python_'s code blocks**: `def`, `class`, +`if`, `for`, `while` and `with`. From 6fe0a982694653b09d2cc0251c1383f981c70231 Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Thu, 19 May 2022 09:52:21 +0300 Subject: [PATCH 13/21] Fix change in CHANGES.md --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index c41f165ee1e..5a0536d6864 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -21,7 +21,7 @@ - Remove redundant parentheses around awaited objects (#2991) - Parentheses around return annotations are now managed (#2990) - Remove unnecessary parentheses from `with` statements (#2926) -- Remove trailing newlines after `def` lines (#3035) +- Remove trailing newlines after code block open (#3035) ### _Blackd_ From 4fd907a9076755681d6401ce964ab20dc9112129 Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Thu, 19 May 2022 11:02:47 +0300 Subject: [PATCH 14/21] Combine all new test cases to one case. --- tests/data/preview/newline_after_def1.py | 8 - tests/data/preview/newline_after_def2.py | 10 - tests/data/preview/newline_after_def3.py | 12 -- tests/data/preview/newline_after_def4.py | 12 -- tests/data/preview/newline_after_def5.py | 10 - tests/data/preview/newline_after_for1.py | 8 - tests/data/preview/newline_after_for2.py | 10 - tests/data/preview/newline_after_for3.py | 11 - tests/data/preview/newline_after_if1.py | 11 - tests/data/preview/newline_after_if2.py | 14 -- tests/data/preview/newline_after_if3.py | 14 -- tests/data/preview/newline_after_while1.py | 8 - tests/data/preview/newline_after_while2.py | 10 - tests/data/preview/newline_after_while3.py | 11 - tests/data/preview/newline_after_with1.py | 8 - tests/data/preview/newline_after_with2.py | 10 - tests/data/preview/newline_after_with3.py | 11 - .../remove_newline_after_code_block_open.py | 189 ++++++++++++++++++ 18 files changed, 189 insertions(+), 178 deletions(-) delete mode 100644 tests/data/preview/newline_after_def1.py delete mode 100644 tests/data/preview/newline_after_def2.py delete mode 100644 tests/data/preview/newline_after_def3.py delete mode 100644 tests/data/preview/newline_after_def4.py delete mode 100644 tests/data/preview/newline_after_def5.py delete mode 100644 tests/data/preview/newline_after_for1.py delete mode 100644 tests/data/preview/newline_after_for2.py delete mode 100644 tests/data/preview/newline_after_for3.py delete mode 100644 tests/data/preview/newline_after_if1.py delete mode 100644 tests/data/preview/newline_after_if2.py delete mode 100644 tests/data/preview/newline_after_if3.py delete mode 100644 tests/data/preview/newline_after_while1.py delete mode 100644 tests/data/preview/newline_after_while2.py delete mode 100644 tests/data/preview/newline_after_while3.py delete mode 100644 tests/data/preview/newline_after_with1.py delete mode 100644 tests/data/preview/newline_after_with2.py delete mode 100644 tests/data/preview/newline_after_with3.py create mode 100644 tests/data/preview/remove_newline_after_code_block_open.py diff --git a/tests/data/preview/newline_after_def1.py b/tests/data/preview/newline_after_def1.py deleted file mode 100644 index 85381b43821..00000000000 --- a/tests/data/preview/newline_after_def1.py +++ /dev/null @@ -1,8 +0,0 @@ -def foo(): - - print("The newline above me should be deleted!") - -# output - -def foo(): - print("The newline above me should be deleted!") diff --git a/tests/data/preview/newline_after_def2.py b/tests/data/preview/newline_after_def2.py deleted file mode 100644 index 2d586583d2a..00000000000 --- a/tests/data/preview/newline_after_def2.py +++ /dev/null @@ -1,10 +0,0 @@ -def foo(): - - - - print("All the newlines above me should be deleted!") - -# output - -def foo(): - print("All the newlines above me should be deleted!") diff --git a/tests/data/preview/newline_after_def3.py b/tests/data/preview/newline_after_def3.py deleted file mode 100644 index 92b7480abec..00000000000 --- a/tests/data/preview/newline_after_def3.py +++ /dev/null @@ -1,12 +0,0 @@ -def f(): - - print("No newline above me!") - - print("There is a newline above me, and that's OK!") - -# output - -def f(): - print("No newline above me!") - - print("There is a newline above me, and that's OK!") diff --git a/tests/data/preview/newline_after_def4.py b/tests/data/preview/newline_after_def4.py deleted file mode 100644 index 4d6717261c8..00000000000 --- a/tests/data/preview/newline_after_def4.py +++ /dev/null @@ -1,12 +0,0 @@ -def foo(): - - # There is a comment here - - print("The newline above me should not be deleted!") - -# output - -def foo(): - # There is a comment here - - print("The newline above me should not be deleted!") diff --git a/tests/data/preview/newline_after_def5.py b/tests/data/preview/newline_after_def5.py deleted file mode 100644 index d6c383ee36a..00000000000 --- a/tests/data/preview/newline_after_def5.py +++ /dev/null @@ -1,10 +0,0 @@ -class Foo: - def bar(self): - - print("The newline above me should be deleted!") - -# output - -class Foo: - def bar(self): - print("The newline above me should be deleted!") diff --git a/tests/data/preview/newline_after_for1.py b/tests/data/preview/newline_after_for1.py deleted file mode 100644 index 51cb3fa541c..00000000000 --- a/tests/data/preview/newline_after_for1.py +++ /dev/null @@ -1,8 +0,0 @@ -for i in range(5): - - print(f"{i}) The line above me should be removed!") - -# output - -for i in range(5): - print(f"{i}) The line above me should be removed!") \ No newline at end of file diff --git a/tests/data/preview/newline_after_for2.py b/tests/data/preview/newline_after_for2.py deleted file mode 100644 index d226e25782e..00000000000 --- a/tests/data/preview/newline_after_for2.py +++ /dev/null @@ -1,10 +0,0 @@ -for i in range(5): - - - - print(f"{i}) The lines above me should be removed!") - -# output - -for i in range(5): - print(f"{i}) The lines above me should be removed!") \ No newline at end of file diff --git a/tests/data/preview/newline_after_for3.py b/tests/data/preview/newline_after_for3.py deleted file mode 100644 index ecb32c8563d..00000000000 --- a/tests/data/preview/newline_after_for3.py +++ /dev/null @@ -1,11 +0,0 @@ -for i in range(5): - - for j in range(7): - - print(f"{i}) The lines above me should be removed!") - -# output - -for i in range(5): - for j in range(7): - print(f"{i}) The lines above me should be removed!") diff --git a/tests/data/preview/newline_after_if1.py b/tests/data/preview/newline_after_if1.py deleted file mode 100644 index d69f0025ee0..00000000000 --- a/tests/data/preview/newline_after_if1.py +++ /dev/null @@ -1,11 +0,0 @@ -import random - -if random.randint(0, 3) == 0: - - print("The new line above me is about to be removed!") - -# output -import random - -if random.randint(0, 3) == 0: - print("The new line above me is about to be removed!") \ No newline at end of file diff --git a/tests/data/preview/newline_after_if2.py b/tests/data/preview/newline_after_if2.py deleted file mode 100644 index f34299f39fa..00000000000 --- a/tests/data/preview/newline_after_if2.py +++ /dev/null @@ -1,14 +0,0 @@ -import random - -if random.randint(0, 3) == 0: - - - - - print("The new lines above me is about to be removed!") - -# output -import random - -if random.randint(0, 3) == 0: - print("The new lines above me is about to be removed!") \ No newline at end of file diff --git a/tests/data/preview/newline_after_if3.py b/tests/data/preview/newline_after_if3.py deleted file mode 100644 index 9db334cf03e..00000000000 --- a/tests/data/preview/newline_after_if3.py +++ /dev/null @@ -1,14 +0,0 @@ -import random - -if random.randint(0, 3) == 0: - - if random.uniform(0, 1) > 0.5: - - print("Two lines above me are about to be removed!") - -# output -import random - -if random.randint(0, 3) == 0: - if random.uniform(0, 1) > 0.5: - print("Two lines above me are about to be removed!") diff --git a/tests/data/preview/newline_after_while1.py b/tests/data/preview/newline_after_while1.py deleted file mode 100644 index 2382aa53b8d..00000000000 --- a/tests/data/preview/newline_after_while1.py +++ /dev/null @@ -1,8 +0,0 @@ -while True: - - print("The newline above me should be deleted!") - -# output - -while True: - print("The newline above me should be deleted!") diff --git a/tests/data/preview/newline_after_while2.py b/tests/data/preview/newline_after_while2.py deleted file mode 100644 index 4976a582ba5..00000000000 --- a/tests/data/preview/newline_after_while2.py +++ /dev/null @@ -1,10 +0,0 @@ -while True: - - - - print("The newlines above me should be deleted!") - -# output - -while True: - print("The newlines above me should be deleted!") diff --git a/tests/data/preview/newline_after_while3.py b/tests/data/preview/newline_after_while3.py deleted file mode 100644 index e2e10b8e363..00000000000 --- a/tests/data/preview/newline_after_while3.py +++ /dev/null @@ -1,11 +0,0 @@ -while True: - - while False: - - print("The newlines above me should be deleted!") - -# output - -while True: - while False: - print("The newlines above me should be deleted!") diff --git a/tests/data/preview/newline_after_with1.py b/tests/data/preview/newline_after_with1.py deleted file mode 100644 index cdbd9fe54e8..00000000000 --- a/tests/data/preview/newline_after_with1.py +++ /dev/null @@ -1,8 +0,0 @@ -with open("/path/to/file.txt", mode="w") as file: - - file.write("The new line above me is about to be removed!") - -# output - -with open("/path/to/file.txt", mode="w") as file: - file.write("The new line above me is about to be removed!") diff --git a/tests/data/preview/newline_after_with2.py b/tests/data/preview/newline_after_with2.py deleted file mode 100644 index e0fb2f07e85..00000000000 --- a/tests/data/preview/newline_after_with2.py +++ /dev/null @@ -1,10 +0,0 @@ -with open("/path/to/file.txt", mode="w") as file: - - - - file.write("The new lines above me is about to be removed!") - -# output - -with open("/path/to/file.txt", mode="w") as file: - file.write("The new lines above me is about to be removed!") diff --git a/tests/data/preview/newline_after_with3.py b/tests/data/preview/newline_after_with3.py deleted file mode 100644 index e6ff391f119..00000000000 --- a/tests/data/preview/newline_after_with3.py +++ /dev/null @@ -1,11 +0,0 @@ -with open("/path/to/file.txt", mode="r") as read_file: - - with open("/path/to/output_file.txt", mode="w") as write_file: - - write_file.writelines(read_file.readlines()) - -# output - -with open("/path/to/file.txt", mode="r") as read_file: - with open("/path/to/output_file.txt", mode="w") as write_file: - write_file.writelines(read_file.readlines()) diff --git a/tests/data/preview/remove_newline_after_code_block_open.py b/tests/data/preview/remove_newline_after_code_block_open.py new file mode 100644 index 00000000000..ef2e5c2f6f5 --- /dev/null +++ b/tests/data/preview/remove_newline_after_code_block_open.py @@ -0,0 +1,189 @@ +import random + + +def foo1(): + + print("The newline above me should be deleted!") + + +def foo2(): + + + + print("All the newlines above me should be deleted!") + + +def foo3(): + + print("No newline above me!") + + print("There is a newline above me, and that's OK!") + + +def foo4(): + + # There is a comment here + + print("The newline above me should not be deleted!") + + +class Foo: + def bar(self): + + print("The newline above me should be deleted!") + + +for i in range(5): + + print(f"{i}) The line above me should be removed!") + + +for i in range(5): + + + + print(f"{i}) The lines above me should be removed!") + + +for i in range(5): + + for j in range(7): + + print(f"{i}) The lines above me should be removed!") + + +if random.randint(0, 3) == 0: + + print("The new line above me is about to be removed!") + + +if random.randint(0, 3) == 0: + + + + + print("The new lines above me is about to be removed!") + + +if random.randint(0, 3) == 0: + if random.uniform(0, 1) > 0.5: + print("Two lines above me are about to be removed!") + + +while True: + + print("The newline above me should be deleted!") + + +while True: + + + + print("The newlines above me should be deleted!") + + +while True: + + while False: + + print("The newlines above me should be deleted!") + + +with open("/path/to/file.txt", mode="w") as file: + + file.write("The new line above me is about to be removed!") + + +with open("/path/to/file.txt", mode="w") as file: + + + + file.write("The new lines above me is about to be removed!") + + +with open("/path/to/file.txt", mode="r") as read_file: + + with open("/path/to/output_file.txt", mode="w") as write_file: + + write_file.writelines(read_file.readlines()) + +# output + +import random + + +def foo1(): + print("The newline above me should be deleted!") + + +def foo2(): + print("All the newlines above me should be deleted!") + + +def foo3(): + print("No newline above me!") + + print("There is a newline above me, and that's OK!") + + +def foo4(): + # There is a comment here + + print("The newline above me should not be deleted!") + + +class Foo: + def bar(self): + print("The newline above me should be deleted!") + + +for i in range(5): + print(f"{i}) The line above me should be removed!") + + +for i in range(5): + print(f"{i}) The lines above me should be removed!") + + +for i in range(5): + for j in range(7): + print(f"{i}) The lines above me should be removed!") + + +if random.randint(0, 3) == 0: + print("The new line above me is about to be removed!") + + +if random.randint(0, 3) == 0: + print("The new lines above me is about to be removed!") + + +if random.randint(0, 3) == 0: + if random.uniform(0, 1) > 0.5: + print("Two lines above me are about to be removed!") + + +while True: + print("The newline above me should be deleted!") + + +while True: + print("The newlines above me should be deleted!") + + +while True: + while False: + print("The newlines above me should be deleted!") + + +with open("/path/to/file.txt", mode="w") as file: + file.write("The new line above me is about to be removed!") + + +with open("/path/to/file.txt", mode="w") as file: + file.write("The new lines above me is about to be removed!") + + +with open("/path/to/file.txt", mode="r") as read_file: + with open("/path/to/output_file.txt", mode="w") as write_file: + write_file.writelines(read_file.readlines()) From b2a015c8c54766a8ccc5981e118d11035c933ec6 Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Thu, 19 May 2022 11:04:50 +0300 Subject: [PATCH 15/21] trim down long description in the future_style.md document --- docs/the_black_code_style/future_style.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/the_black_code_style/future_style.md b/docs/the_black_code_style/future_style.md index 7a3cddb4231..3d8f70633ae 100644 --- a/docs/the_black_code_style/future_style.md +++ b/docs/the_black_code_style/future_style.md @@ -52,11 +52,8 @@ tracked in [this issue](https://github.com/psf/black/issues/2188). ### Removing trailing newlines after code block open -Newlines are great. They help us organize our code and leave room for the coders and -reviewers to breath. However, too many newlines can make simple code gigantic and -massive. This is unnecessary in a lot of cases. In order to reduce the number of -redundant newlines, _Black_ will remove trailing newlines after code block openings. -That means that the following code: +_Black_ will remove trailing newlines after code block openings. That means that the +following code: ```python def my_func(): @@ -66,7 +63,7 @@ def my_func(): print("But the line above me won't!") ``` -Will change to: +Will be changed to: ```python def my_func(): From e496d90aff5d6cc241ae7dfb3d719c8d90bff354 Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Wed, 25 May 2022 11:33:12 +0300 Subject: [PATCH 16/21] Rename `remove_def_trailing_newline` to `remove_block_trailing_newline` --- src/black/lines.py | 2 +- src/black/mode.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/black/lines.py b/src/black/lines.py index 6cb88d8242c..8b591c324a5 100644 --- a/src/black/lines.py +++ b/src/black/lines.py @@ -521,7 +521,7 @@ def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]: return before, 1 if ( - Preview.remove_def_trailing_newline in current_line.mode + Preview.remove_block_trailing_newline in current_line.mode and self.previous_line and self.previous_line.opens_block ): diff --git a/src/black/mode.py b/src/black/mode.py index f72c468a46e..cad6cd2a4c4 100644 --- a/src/black/mode.py +++ b/src/black/mode.py @@ -148,7 +148,7 @@ class Preview(Enum): one_element_subscript = auto() annotation_parens = auto() long_docstring_quotes_on_newline = auto() - remove_def_trailing_newline = auto() + remove_block_trailing_newline = auto() class Deprecated(UserWarning): From 860941b6fe8c05cb7e8ac7c10ec31ec36419674d Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Thu, 26 May 2022 18:47:21 +0300 Subject: [PATCH 17/21] Update docs/the_black_code_style/future_style.md Co-authored-by: Jelle Zijlstra --- docs/the_black_code_style/future_style.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/the_black_code_style/future_style.md b/docs/the_black_code_style/future_style.md index 3d8f70633ae..cd769b33aa5 100644 --- a/docs/the_black_code_style/future_style.md +++ b/docs/the_black_code_style/future_style.md @@ -72,5 +72,5 @@ def my_func(): print("But the line above me won't!") ``` -This new feature will be applied to **all _Python_'s code blocks**: `def`, `class`, +This new feature will be applied to **all code blocks**: `def`, `class`, `if`, `for`, `while` and `with`. From f44edba13ef44bdf3676dcf9f467fdaefc32eb5d Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Thu, 26 May 2022 18:49:53 +0300 Subject: [PATCH 18/21] Fix linting issue --- docs/the_black_code_style/future_style.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/the_black_code_style/future_style.md b/docs/the_black_code_style/future_style.md index cd769b33aa5..49ef9a039c5 100644 --- a/docs/the_black_code_style/future_style.md +++ b/docs/the_black_code_style/future_style.md @@ -72,5 +72,5 @@ def my_func(): print("But the line above me won't!") ``` -This new feature will be applied to **all code blocks**: `def`, `class`, -`if`, `for`, `while` and `with`. +This new feature will be applied to **all code blocks**: `def`, `class`, `if`, `for`, +`while` and `with`. From 24b48cab31458be306dec85f6c8a2b446ee4a775 Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Thu, 26 May 2022 18:53:07 +0300 Subject: [PATCH 19/21] Add new preview feature test for `match`-`case` blocks --- .../preview_310/remove_newline_after match.py | 31 +++++++++++++++++++ tests/test_format.py | 7 +++++ 2 files changed, 38 insertions(+) create mode 100644 tests/data/preview_310/remove_newline_after match.py diff --git a/tests/data/preview_310/remove_newline_after match.py b/tests/data/preview_310/remove_newline_after match.py new file mode 100644 index 00000000000..eac6488704e --- /dev/null +++ b/tests/data/preview_310/remove_newline_after match.py @@ -0,0 +1,31 @@ +def http_status(status): + + match status: + + case 400: + + return "Bad request" + + case 401: + + return "Unauthorized" + + case 403: + + return "Forbidden" + + case 404: + + return "Not found" + +# output +def http_status(status): + match status: + case 400: + return "Bad request" + case 401: + return "Unauthorized" + case 403: + return "Forbidden" + case 404: + return "Not found" \ No newline at end of file diff --git a/tests/test_format.py b/tests/test_format.py index 005a5771c2b..a8a922d17db 100644 --- a/tests/test_format.py +++ b/tests/test_format.py @@ -86,6 +86,13 @@ def test_preview_minimum_python_39_format(filename: str) -> None: assert_format(source, expected, mode, minimum_version=(3, 9)) +@pytest.mark.parametrize("filename", all_data_cases("preview_310")) +def test_preview_minimum_python_310_format(filename: str) -> None: + source, expected = read_data("preview_310", filename) + mode = black.Mode(preview=True) + assert_format(source, expected, mode, minimum_version=(3, 10)) + + @pytest.mark.parametrize("filename", SOURCES) def test_source_is_formatted(filename: str) -> None: check_file("", filename, DEFAULT_MODE, data=False) From 92ce12c49a4e7c3c8c22bedfbdd25a901d91b5ba Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Thu, 26 May 2022 18:57:04 +0300 Subject: [PATCH 20/21] Fix failing test --- tests/data/preview_310/remove_newline_after match.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/data/preview_310/remove_newline_after match.py b/tests/data/preview_310/remove_newline_after match.py index eac6488704e..f7bcfbf27a2 100644 --- a/tests/data/preview_310/remove_newline_after match.py +++ b/tests/data/preview_310/remove_newline_after match.py @@ -23,9 +23,12 @@ def http_status(status): match status: case 400: return "Bad request" + case 401: return "Unauthorized" + case 403: return "Forbidden" + case 404: return "Not found" \ No newline at end of file From ee5888ba9f971039ebad003a678dfb58c9f47e7d Mon Sep 17 00:00:00 2001 From: Sagi Shadur Date: Thu, 26 May 2022 23:42:06 +0300 Subject: [PATCH 21/21] Add `case` and `match` to code blocks list --- docs/the_black_code_style/future_style.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/the_black_code_style/future_style.md b/docs/the_black_code_style/future_style.md index 49ef9a039c5..8d159e9b0a2 100644 --- a/docs/the_black_code_style/future_style.md +++ b/docs/the_black_code_style/future_style.md @@ -73,4 +73,4 @@ def my_func(): ``` This new feature will be applied to **all code blocks**: `def`, `class`, `if`, `for`, -`while` and `with`. +`while`, `with`, `case` and `match`.