diff --git a/crates/ruff_python_formatter/src/statement/suite.rs b/crates/ruff_python_formatter/src/statement/suite.rs index bee3f00127e13..5bfd8ed4c0601 100644 --- a/crates/ruff_python_formatter/src/statement/suite.rs +++ b/crates/ruff_python_formatter/src/statement/suite.rs @@ -58,17 +58,13 @@ impl FormatRule> for FormatSuite { return Ok(()); }; - // First entry has never any separator, doesn't matter which one we take; + // First entry has never any separator, doesn't matter which one we take. joiner.entry(first, &first.format()); let mut last = first; - let mut is_last_function_or_class_definition = is_class_or_function_definition(first); for statement in iter { - let is_current_function_or_class_definition = - is_class_or_function_definition(statement); - - if is_last_function_or_class_definition || is_current_function_or_class_definition { + if is_class_or_function_definition(last) || is_class_or_function_definition(statement) { match self.level { SuiteLevel::TopLevel => { joiner.entry_with_separator( @@ -81,6 +77,8 @@ impl FormatRule> for FormatSuite { joiner.entry_with_separator(&empty_line(), &statement.format(), statement); } } + } else if is_import_definition(last) && !is_import_definition(statement) { + joiner.entry_with_separator(&empty_line(), &statement.format(), statement); } else if is_compound_statement(last) { // Handles the case where a body has trailing comments. The issue is that RustPython does not include // the comments in the range of the suite. This means, the body ends right after the last statement in the body. @@ -124,7 +122,6 @@ impl FormatRule> for FormatSuite { joiner.entry(statement, &statement.format()); } - is_last_function_or_class_definition = is_current_function_or_class_definition; last = statement; } @@ -143,6 +140,10 @@ const fn is_class_or_function_definition(stmt: &Stmt) -> bool { ) } +const fn is_import_definition(stmt: &Stmt) -> bool { + matches!(stmt, Stmt::Import(_) | Stmt::ImportFrom(_)) +} + impl FormatRuleWithOptions> for FormatSuite { type Options = SuiteLevel; diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtonoff.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtonoff.py.snap index 1f83b05cc2962..1cc7c53d39690 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtonoff.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtonoff.py.snap @@ -198,20 +198,21 @@ d={'a':1, ```diff --- Black +++ Ruff -@@ -6,10 +6,9 @@ +@@ -6,10 +6,10 @@ from library import some_connection, some_decorator # fmt: off -from third_party import (X, - Y, Z) +from third_party import X, Y, Z ++ # fmt: on -f"trigger 3.6 mode" +f"NOT_YET_IMPLEMENTED_ExprJoinedStr" # Comment 1 # Comment 2 -@@ -17,26 +16,40 @@ +@@ -17,26 +17,40 @@ # fmt: off def func_no_args(): @@ -270,7 +271,7 @@ d={'a':1, # fmt: on def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""): offset = attr.ib(default=attr.Factory(lambda: _r.uniform(1, 2))) -@@ -63,15 +76,15 @@ +@@ -63,15 +77,15 @@ something = { # fmt: off @@ -289,13 +290,14 @@ d={'a':1, # fmt: on goes + here, andhere, -@@ -80,38 +93,35 @@ +@@ -80,38 +94,36 @@ def import_as_names(): # fmt: off - from hello import a, b - 'unformatted' + from hello import a, b ++ + "unformatted" # fmt: on @@ -338,7 +340,7 @@ d={'a':1, # fmt: on -@@ -132,10 +142,10 @@ +@@ -132,10 +144,10 @@ """Another known limitation.""" # fmt: on # fmt: off @@ -353,7 +355,7 @@ d={'a':1, # fmt: on # fmt: off # ...but comments still get reformatted even though they should not be -@@ -153,9 +163,7 @@ +@@ -153,9 +165,7 @@ ) ) # fmt: off @@ -364,7 +366,7 @@ d={'a':1, # fmt: on _type_comment_re = re.compile( r""" -@@ -178,7 +186,7 @@ +@@ -178,7 +188,7 @@ $ """, # fmt: off @@ -373,7 +375,7 @@ d={'a':1, # fmt: on ) -@@ -216,8 +224,7 @@ +@@ -216,8 +226,7 @@ xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5, ) # fmt: off @@ -399,6 +401,7 @@ from third_party import X, Y, Z from library import some_connection, some_decorator # fmt: off from third_party import X, Y, Z + # fmt: on f"NOT_YET_IMPLEMENTED_ExprJoinedStr" # Comment 1 @@ -486,6 +489,7 @@ def subscriptlist(): def import_as_names(): # fmt: off from hello import a, b + "unformatted" # fmt: on diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__function.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__function.py.snap index d300b64696055..9e903ec50c900 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__function.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__function.py.snap @@ -107,17 +107,16 @@ def __await__(): return (yield) ```diff --- Black +++ Ruff -@@ -5,8 +5,7 @@ - from third_party import X, Y, Z +@@ -6,7 +6,7 @@ from library import some_connection, some_decorator -- + -f"trigger 3.6 mode" +f"NOT_YET_IMPLEMENTED_ExprJoinedStr" def func_no_args(): -@@ -65,18 +64,14 @@ +@@ -65,18 +65,14 @@ def spaces2(result=_core.Value(None)): assert fut is self._read_fut, (fut, self._read_fut) @@ -153,6 +152,7 @@ import sys from third_party import X, Y, Z from library import some_connection, some_decorator + f"NOT_YET_IMPLEMENTED_ExprJoinedStr"