<!-- Changes that affect Black's preview style -->
+- More concise formatting for dummy implementations (#3796)
+
### Configuration
<!-- Changes to how Black can be configured -->
def visit_suite(self, node: Node) -> Iterator[Line]:
"""Visit a suite."""
- if self.mode.is_pyi and is_stub_suite(node):
+ if (
+ self.mode.is_pyi or Preview.dummy_implementations in self.mode
+ ) and is_stub_suite(node):
yield from self.visit(node.children[2])
else:
yield from self.visit_default(node)
is_suite_like = node.parent and node.parent.type in STATEMENT
if is_suite_like:
- if self.mode.is_pyi and is_stub_body(node):
+ if (
+ self.mode.is_pyi or Preview.dummy_implementations in self.mode
+ ) and is_stub_body(node):
yield from self.visit_default(node)
else:
yield from self.line(+1)
else:
if (
- not self.mode.is_pyi
+ not (self.mode.is_pyi or Preview.dummy_implementations in self.mode)
or not node.parent
or not is_stub_suite(node.parent)
):
and second_leaf.value == "def"
)
+ @property
+ def is_stub_def(self) -> bool:
+ """Is this line a function definition with a body consisting only of "..."?"""
+ return self.is_def and self.leaves[-4:] == [Leaf(token.COLON, ":")] + [
+ Leaf(token.DOT, ".") for _ in range(3)
+ ]
+
@property
def is_class_paren_empty(self) -> bool:
"""Is this a class with no base classes but using parentheses?
first_leaf.prefix = ""
else:
before = 0
+
+ user_had_newline = bool(before)
depth = current_line.depth
previous_def = None
if self.mode.is_pyi:
if depth and not current_line.is_def and self.previous_line.is_def:
# Empty lines between attributes and methods should be preserved.
- before = min(1, before)
+ before = 1 if user_had_newline else 0
elif (
Preview.blank_line_after_nested_stub_class in self.mode
and previous_def.is_class
before = 2
if current_line.is_decorator or current_line.is_def or current_line.is_class:
- return self._maybe_empty_lines_for_class_or_def(current_line, before)
+ return self._maybe_empty_lines_for_class_or_def(
+ current_line, before, user_had_newline
+ )
if (
self.previous_line
return 0, 0
return before, 0
- def _maybe_empty_lines_for_class_or_def(
- self, current_line: Line, before: int
+ def _maybe_empty_lines_for_class_or_def( # noqa: C901
+ self, current_line: Line, before: int, user_had_newline: bool
) -> Tuple[int, int]:
if not current_line.is_decorator:
self.previous_defs.append(current_line)
newlines = 0
else:
newlines = 1 if current_line.depth else 2
+ # If a user has left no space after a dummy implementation, don't insert
+ # new lines. This is useful for instance for @overload or Protocols.
+ if (
+ Preview.dummy_implementations in self.mode
+ and self.previous_line.is_stub_def
+ and not user_had_newline
+ ):
+ newlines = 0
if comment_to_add_newlines is not None:
previous_block = comment_to_add_newlines.previous_block
if previous_block is not None:
skip_magic_trailing_comma_in_subscript = auto()
wrap_long_dict_values_in_parens = auto()
wrap_multiple_context_managers_in_parens = auto()
+ dummy_implementations = auto()
class Deprecated(UserWarning):
# The input source must not contain any Py36-specific syntax (e.g. argument type
# annotations, trailing comma after *rest) or this test becomes invalid.
-def long_function_name(argument_one, argument_two, argument_three, argument_four, argument_five, argument_six, *rest): ...
+def long_function_name(argument_one, argument_two, argument_three, argument_four, argument_five, argument_six, *rest): pass
# output
# The input source must not contain any Py36-specific syntax (e.g. argument type
# annotations, trailing comma after *rest) or this test becomes invalid.
argument_six,
*rest,
):
- ...
+ pass
)
def test_fails_invalid_post_data(
self, pyramid_config, db_request, post_data, message
- ):
- ...
+ ): ...
square = Square(4) # type: Optional[Square]
--- /dev/null
+from typing import NoReturn, Protocol, Union, overload
+
+
+def dummy(a): ...
+def other(b): ...
+
+
+@overload
+def a(arg: int) -> int: ...
+@overload
+def a(arg: str) -> str: ...
+@overload
+def a(arg: object) -> NoReturn: ...
+def a(arg: Union[int, str, object]) -> Union[int, str]:
+ if not isinstance(arg, (int, str)):
+ raise TypeError
+ return arg
+
+class Proto(Protocol):
+ def foo(self, a: int) -> int:
+ ...
+
+ def bar(self, b: str) -> str: ...
+ def baz(self, c: bytes) -> str:
+ ...
+
+
+def dummy_two():
+ ...
+@dummy
+def dummy_three():
+ ...
+
+def dummy_four():
+ ...
+
+@overload
+def b(arg: int) -> int: ...
+
+@overload
+def b(arg: str) -> str: ...
+@overload
+def b(arg: object) -> NoReturn: ...
+
+def b(arg: Union[int, str, object]) -> Union[int, str]:
+ if not isinstance(arg, (int, str)):
+ raise TypeError
+ return arg
+
+# output
+
+from typing import NoReturn, Protocol, Union, overload
+
+
+def dummy(a): ...
+def other(b): ...
+
+
+@overload
+def a(arg: int) -> int: ...
+@overload
+def a(arg: str) -> str: ...
+@overload
+def a(arg: object) -> NoReturn: ...
+def a(arg: Union[int, str, object]) -> Union[int, str]:
+ if not isinstance(arg, (int, str)):
+ raise TypeError
+ return arg
+
+
+class Proto(Protocol):
+ def foo(self, a: int) -> int: ...
+
+ def bar(self, b: str) -> str: ...
+ def baz(self, c: bytes) -> str: ...
+
+
+def dummy_two(): ...
+@dummy
+def dummy_three(): ...
+
+
+def dummy_four(): ...
+
+
+@overload
+def b(arg: int) -> int: ...
+
+
+@overload
+def b(arg: str) -> str: ...
+@overload
+def b(arg: object) -> NoReturn: ...
+
+
+def b(arg: Union[int, str, object]) -> Union[int, str]:
+ if not isinstance(arg, (int, str)):
+ raise TypeError
+ return arg