Repository: psf/black

Issue:
Preview style: Don't collapse dummy implementation with comment
I found this change in our test suite while trying to stabilize the preview style:

```
 match command.split():
     case ["north"] | ["go", "north"]:
         current_room = current_room.neighbor("north")
-    case ["get", obj] | ["pick", "up", obj] | ["pick", obj, "up"]:
-        ...  # Code for picking up the given object
+    case (
+        ["get", obj] | ["pick", "up", obj] | ["pick", obj, "up"]
+    ): ...  # Code for picking up the given object
```

This is from the `dummy_implementation` preview change, #3796.

I think the new code looks worse here; we shouldn't use the dummy_implementation branch if there is a comment after the ellipsis.


Discussion:

Resolving patch:
diff --git a/src/black/linegen.py b/src/black/linegen.py
--- a/src/black/linegen.py
+++ b/src/black/linegen.py
@@ -286,7 +286,7 @@ def visit_suite(self, node: Node) -> Iterator[Line]:
         """Visit a suite."""
         if (
             self.mode.is_pyi or Preview.dummy_implementations in self.mode
-        ) and is_stub_suite(node):
+        ) and is_stub_suite(node, self.mode):
             yield from self.visit(node.children[2])
         else:
             yield from self.visit_default(node)
@@ -314,7 +314,7 @@ def visit_simple_stmt(self, node: Node) -> Iterator[Line]:
             if (
                 not (self.mode.is_pyi or Preview.dummy_implementations in self.mode)
                 or not node.parent
-                or not is_stub_suite(node.parent)
+                or not is_stub_suite(node.parent, self.mode)
             ):
                 yield from self.line()
             yield from self.visit_default(node)
diff --git a/src/black/nodes.py b/src/black/nodes.py
--- a/src/black/nodes.py
+++ b/src/black/nodes.py
@@ -736,8 +736,15 @@ def is_funcdef(node: Node) -> bool:
     return node.type == syms.funcdef
 
 
-def is_stub_suite(node: Node) -> bool:
+def is_stub_suite(node: Node, mode: Mode) -> bool:
     """Return True if `node` is a suite with a stub body."""
+    if node.parent is not None:
+        if Preview.dummy_implementations in mode and node.parent.type not in (
+            syms.funcdef,
+            syms.async_funcdef,
+            syms.classdef,
+        ):
+            return False
 
     # If there is a comment, we want to keep it.
     if node.prefix.strip():


Test patch:
diff --git a/tests/data/cases/preview_dummy_implementations.py b/tests/data/cases/preview_dummy_implementations.py
--- a/tests/data/cases/preview_dummy_implementations.py
+++ b/tests/data/cases/preview_dummy_implementations.py
@@ -1,9 +1,11 @@
 # flags: --preview
 from typing import NoReturn, Protocol, Union, overload
 
+class Empty:
+    ...
 
 def dummy(a): ...
-def other(b): ...
+async def other(b): ...
 
 
 @overload
@@ -48,13 +50,22 @@ def b(arg: Union[int, str, object]) -> Union[int, str]:
         raise TypeError
     return arg
 
+def has_comment():
+    ...  # still a dummy
+
+if some_condition:
+    ...
+
 # output
 
 from typing import NoReturn, Protocol, Union, overload
 
 
+class Empty: ...
+
+
 def dummy(a): ...
-def other(b): ...
+async def other(b): ...
 
 
 @overload
@@ -98,3 +109,10 @@ def b(arg: Union[int, str, object]) -> Union[int, str]:
     if not isinstance(arg, (int, str)):
         raise TypeError
     return arg
+
+
+def has_comment(): ...  # still a dummy
+
+
+if some_condition:
+    ...