More concise formatting for dummy implementations (#3796)
This commit is contained in:
parent
59e8936768
commit
c160e4b7ce
@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
<!-- Changes that affect Black's preview style -->
|
<!-- Changes that affect Black's preview style -->
|
||||||
|
|
||||||
|
- More concise formatting for dummy implementations (#3796)
|
||||||
|
|
||||||
### Configuration
|
### Configuration
|
||||||
|
|
||||||
<!-- Changes to how Black can be configured -->
|
<!-- Changes to how Black can be configured -->
|
||||||
|
@ -281,7 +281,9 @@ def visit_match_case(self, node: Node) -> Iterator[Line]:
|
|||||||
|
|
||||||
def visit_suite(self, node: Node) -> Iterator[Line]:
|
def visit_suite(self, node: Node) -> Iterator[Line]:
|
||||||
"""Visit a suite."""
|
"""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])
|
yield from self.visit(node.children[2])
|
||||||
else:
|
else:
|
||||||
yield from self.visit_default(node)
|
yield from self.visit_default(node)
|
||||||
@ -296,7 +298,9 @@ def visit_simple_stmt(self, node: Node) -> Iterator[Line]:
|
|||||||
|
|
||||||
is_suite_like = node.parent and node.parent.type in STATEMENT
|
is_suite_like = node.parent and node.parent.type in STATEMENT
|
||||||
if is_suite_like:
|
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)
|
yield from self.visit_default(node)
|
||||||
else:
|
else:
|
||||||
yield from self.line(+1)
|
yield from self.line(+1)
|
||||||
@ -305,7 +309,7 @@ def visit_simple_stmt(self, node: Node) -> Iterator[Line]:
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
if (
|
if (
|
||||||
not self.mode.is_pyi
|
not (self.mode.is_pyi or Preview.dummy_implementations in self.mode)
|
||||||
or not node.parent
|
or not node.parent
|
||||||
or not is_stub_suite(node.parent)
|
or not is_stub_suite(node.parent)
|
||||||
):
|
):
|
||||||
|
@ -165,6 +165,13 @@ def is_def(self) -> bool:
|
|||||||
and second_leaf.value == "def"
|
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
|
@property
|
||||||
def is_class_paren_empty(self) -> bool:
|
def is_class_paren_empty(self) -> bool:
|
||||||
"""Is this a class with no base classes but using parentheses?
|
"""Is this a class with no base classes but using parentheses?
|
||||||
@ -578,6 +585,8 @@ def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
|
|||||||
first_leaf.prefix = ""
|
first_leaf.prefix = ""
|
||||||
else:
|
else:
|
||||||
before = 0
|
before = 0
|
||||||
|
|
||||||
|
user_had_newline = bool(before)
|
||||||
depth = current_line.depth
|
depth = current_line.depth
|
||||||
|
|
||||||
previous_def = None
|
previous_def = None
|
||||||
@ -589,7 +598,7 @@ def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
|
|||||||
if self.mode.is_pyi:
|
if self.mode.is_pyi:
|
||||||
if depth and not current_line.is_def and self.previous_line.is_def:
|
if depth and not current_line.is_def and self.previous_line.is_def:
|
||||||
# Empty lines between attributes and methods should be preserved.
|
# Empty lines between attributes and methods should be preserved.
|
||||||
before = min(1, before)
|
before = 1 if user_had_newline else 0
|
||||||
elif (
|
elif (
|
||||||
Preview.blank_line_after_nested_stub_class in self.mode
|
Preview.blank_line_after_nested_stub_class in self.mode
|
||||||
and previous_def.is_class
|
and previous_def.is_class
|
||||||
@ -624,7 +633,9 @@ def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
|
|||||||
before = 2
|
before = 2
|
||||||
|
|
||||||
if current_line.is_decorator or current_line.is_def or current_line.is_class:
|
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 (
|
if (
|
||||||
self.previous_line
|
self.previous_line
|
||||||
@ -648,8 +659,8 @@ def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
|
|||||||
return 0, 0
|
return 0, 0
|
||||||
return before, 0
|
return before, 0
|
||||||
|
|
||||||
def _maybe_empty_lines_for_class_or_def(
|
def _maybe_empty_lines_for_class_or_def( # noqa: C901
|
||||||
self, current_line: Line, before: int
|
self, current_line: Line, before: int, user_had_newline: bool
|
||||||
) -> Tuple[int, int]:
|
) -> Tuple[int, int]:
|
||||||
if not current_line.is_decorator:
|
if not current_line.is_decorator:
|
||||||
self.previous_defs.append(current_line)
|
self.previous_defs.append(current_line)
|
||||||
@ -715,6 +726,14 @@ def _maybe_empty_lines_for_class_or_def(
|
|||||||
newlines = 0
|
newlines = 0
|
||||||
else:
|
else:
|
||||||
newlines = 1 if current_line.depth else 2
|
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:
|
if comment_to_add_newlines is not None:
|
||||||
previous_block = comment_to_add_newlines.previous_block
|
previous_block = comment_to_add_newlines.previous_block
|
||||||
if previous_block is not None:
|
if previous_block is not None:
|
||||||
|
@ -182,6 +182,7 @@ class Preview(Enum):
|
|||||||
skip_magic_trailing_comma_in_subscript = auto()
|
skip_magic_trailing_comma_in_subscript = auto()
|
||||||
wrap_long_dict_values_in_parens = auto()
|
wrap_long_dict_values_in_parens = auto()
|
||||||
wrap_multiple_context_managers_in_parens = auto()
|
wrap_multiple_context_managers_in_parens = auto()
|
||||||
|
dummy_implementations = auto()
|
||||||
|
|
||||||
|
|
||||||
class Deprecated(UserWarning):
|
class Deprecated(UserWarning):
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# The input source must not contain any Py36-specific syntax (e.g. argument type
|
# The input source must not contain any Py36-specific syntax (e.g. argument type
|
||||||
# annotations, trailing comma after *rest) or this test becomes invalid.
|
# 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
|
# output
|
||||||
# The input source must not contain any Py36-specific syntax (e.g. argument type
|
# The input source must not contain any Py36-specific syntax (e.g. argument type
|
||||||
# annotations, trailing comma after *rest) or this test becomes invalid.
|
# annotations, trailing comma after *rest) or this test becomes invalid.
|
||||||
@ -13,4 +13,4 @@ def long_function_name(
|
|||||||
argument_six,
|
argument_six,
|
||||||
*rest,
|
*rest,
|
||||||
):
|
):
|
||||||
...
|
pass
|
||||||
|
@ -278,8 +278,7 @@ class C:
|
|||||||
)
|
)
|
||||||
def test_fails_invalid_post_data(
|
def test_fails_invalid_post_data(
|
||||||
self, pyramid_config, db_request, post_data, message
|
self, pyramid_config, db_request, post_data, message
|
||||||
):
|
): ...
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
square = Square(4) # type: Optional[Square]
|
square = Square(4) # type: Optional[Square]
|
||||||
|
99
tests/data/preview/dummy_implementations.py
Normal file
99
tests/data/preview/dummy_implementations.py
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
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
|
Loading…
Reference in New Issue
Block a user