Create the 2024 stable style (#4106)
This commit is contained in:
parent
8fe602b1fa
commit
59b9d858a3
40
CHANGES.md
40
CHANGES.md
@ -6,22 +6,54 @@
|
|||||||
|
|
||||||
<!-- Include any especially major or disruptive changes here -->
|
<!-- Include any especially major or disruptive changes here -->
|
||||||
|
|
||||||
|
This release introduces the new 2024 stable style (#4106), stabilizing the following
|
||||||
|
changes:
|
||||||
|
|
||||||
|
- Add parentheses around `if`-`else` expressions (#2278)
|
||||||
|
- Dummy class and function implementations consisting only of `...` are formatted more
|
||||||
|
compactly (#3796)
|
||||||
|
- If an assignment statement is too long, we now prefer splitting on the right-hand side
|
||||||
|
(#3368)
|
||||||
|
- Hex codes in Unicode escape sequences are now standardized to lowercase (#2916)
|
||||||
|
- Allow empty first lines at the beginning of most blocks (#3967, #4061)
|
||||||
|
- Add parentheses around long type annotations (#3899)
|
||||||
|
- Standardize on a single newline after module docstrings (#3932)
|
||||||
|
- Fix incorrect magic trailing comma handling in return types (#3916)
|
||||||
|
- Remove blank lines before class docstrings (#3692)
|
||||||
|
- Wrap multiple context managers in parentheses if combined in a single `with` statement
|
||||||
|
(#3489)
|
||||||
|
- Fix bug in line length calculations for power operations (#3942)
|
||||||
|
- Add trailing commas to collection literals even if there's a comment after the last
|
||||||
|
entry (#3393)
|
||||||
|
- When using `--skip-magic-trailing-comma` or `-C`, trailing commas are stripped from
|
||||||
|
subscript expressions with more than 1 element (#3209)
|
||||||
|
- Add extra blank lines in stubs in a few cases (#3564, #3862)
|
||||||
|
- Accept raw strings as docstrings (#3947)
|
||||||
|
- Split long lines in case blocks (#4024)
|
||||||
|
- Stop removing spaces from walrus operators within subscripts (#3823)
|
||||||
|
- Fix incorrect formatting of certain async statements (#3609)
|
||||||
|
- Allow combining `# fmt: skip` with other comments (#3959)
|
||||||
|
|
||||||
### Stable style
|
### Stable style
|
||||||
|
|
||||||
<!-- Changes that affect Black's stable style -->
|
<!-- Changes that affect Black's stable style -->
|
||||||
|
|
||||||
### Preview style
|
Several bug fixes were made in features that are moved to the stable style in this
|
||||||
|
release:
|
||||||
<!-- Changes that affect Black's preview style -->
|
|
||||||
|
|
||||||
- Fix comment handling when parenthesising conditional expressions (#4134)
|
- Fix comment handling when parenthesising conditional expressions (#4134)
|
||||||
- Format module docstrings the same as class and function docstrings (#4095)
|
|
||||||
- Fix bug where spaces were not added around parenthesized walruses in subscripts,
|
- Fix bug where spaces were not added around parenthesized walruses in subscripts,
|
||||||
unlike other binary operators (#4109)
|
unlike other binary operators (#4109)
|
||||||
- Remove empty lines before docstrings in async functions (#4132)
|
- Remove empty lines before docstrings in async functions (#4132)
|
||||||
- Address a missing case in the change to allow empty lines at the beginning of all
|
- Address a missing case in the change to allow empty lines at the beginning of all
|
||||||
blocks, except immediately before a docstring (#4130)
|
blocks, except immediately before a docstring (#4130)
|
||||||
- For stubs, fix logic to enforce empty line after nested classes with bodies (#4141)
|
- For stubs, fix logic to enforce empty line after nested classes with bodies (#4141)
|
||||||
|
|
||||||
|
### Preview style
|
||||||
|
|
||||||
|
<!-- Changes that affect Black's preview style -->
|
||||||
|
|
||||||
|
- Format module docstrings the same as class and function docstrings (#4095)
|
||||||
- Fix crash when using a walrus in a dictionary (#4155)
|
- Fix crash when using a walrus in a dictionary (#4155)
|
||||||
- Fix unnecessary parentheses when wrapping long dicts (#4135)
|
- Fix unnecessary parentheses when wrapping long dicts (#4135)
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from typing import Collection, Final, Iterator, List, Optional, Tuple, Union
|
from typing import Collection, Final, Iterator, List, Optional, Tuple, Union
|
||||||
|
|
||||||
from black.mode import Mode, Preview
|
from black.mode import Mode
|
||||||
from black.nodes import (
|
from black.nodes import (
|
||||||
CLOSING_BRACKETS,
|
CLOSING_BRACKETS,
|
||||||
STANDALONE_COMMENT,
|
STANDALONE_COMMENT,
|
||||||
@ -390,22 +390,18 @@ def _contains_fmt_skip_comment(comment_line: str, mode: Mode) -> bool:
|
|||||||
# noqa:XXX # fmt:skip # a nice line <-- multiple comments (Preview)
|
# noqa:XXX # fmt:skip # a nice line <-- multiple comments (Preview)
|
||||||
# pylint:XXX; fmt:skip <-- list of comments (; separated, Preview)
|
# pylint:XXX; fmt:skip <-- list of comments (; separated, Preview)
|
||||||
"""
|
"""
|
||||||
semantic_comment_blocks = (
|
semantic_comment_blocks = [
|
||||||
[
|
comment_line,
|
||||||
comment_line,
|
*[
|
||||||
*[
|
_COMMENT_PREFIX + comment.strip()
|
||||||
_COMMENT_PREFIX + comment.strip()
|
for comment in comment_line.split(_COMMENT_PREFIX)[1:]
|
||||||
for comment in comment_line.split(_COMMENT_PREFIX)[1:]
|
],
|
||||||
],
|
*[
|
||||||
*[
|
_COMMENT_PREFIX + comment.strip()
|
||||||
_COMMENT_PREFIX + comment.strip()
|
for comment in comment_line.strip(_COMMENT_PREFIX).split(
|
||||||
for comment in comment_line.strip(_COMMENT_PREFIX).split(
|
_COMMENT_LIST_SEPARATOR
|
||||||
_COMMENT_LIST_SEPARATOR
|
)
|
||||||
)
|
],
|
||||||
],
|
]
|
||||||
]
|
|
||||||
if Preview.single_line_format_skip_with_multiple_comments in mode
|
|
||||||
else [comment_line]
|
|
||||||
)
|
|
||||||
|
|
||||||
return any(comment in FMT_SKIP for comment in semantic_comment_blocks)
|
return any(comment in FMT_SKIP for comment in semantic_comment_blocks)
|
||||||
|
@ -115,10 +115,8 @@ def line(self, indent: int = 0) -> Iterator[Line]:
|
|||||||
self.current_line.depth += indent
|
self.current_line.depth += indent
|
||||||
return # Line is empty, don't emit. Creating a new one unnecessary.
|
return # Line is empty, don't emit. Creating a new one unnecessary.
|
||||||
|
|
||||||
if (
|
if len(self.current_line.leaves) == 1 and is_async_stmt_or_funcdef(
|
||||||
Preview.improved_async_statements_handling in self.mode
|
self.current_line.leaves[0]
|
||||||
and len(self.current_line.leaves) == 1
|
|
||||||
and is_async_stmt_or_funcdef(self.current_line.leaves[0])
|
|
||||||
):
|
):
|
||||||
# Special case for async def/for/with statements. `visit_async_stmt`
|
# Special case for async def/for/with statements. `visit_async_stmt`
|
||||||
# adds an `ASYNC` leaf then visits the child def/for/with statement
|
# adds an `ASYNC` leaf then visits the child def/for/with statement
|
||||||
@ -164,20 +162,19 @@ def visit_default(self, node: LN) -> Iterator[Line]:
|
|||||||
def visit_test(self, node: Node) -> Iterator[Line]:
|
def visit_test(self, node: Node) -> Iterator[Line]:
|
||||||
"""Visit an `x if y else z` test"""
|
"""Visit an `x if y else z` test"""
|
||||||
|
|
||||||
if Preview.parenthesize_conditional_expressions in self.mode:
|
already_parenthesized = (
|
||||||
already_parenthesized = (
|
node.prev_sibling and node.prev_sibling.type == token.LPAR
|
||||||
node.prev_sibling and node.prev_sibling.type == token.LPAR
|
)
|
||||||
)
|
|
||||||
|
|
||||||
if not already_parenthesized:
|
if not already_parenthesized:
|
||||||
# Similar to logic in wrap_in_parentheses
|
# Similar to logic in wrap_in_parentheses
|
||||||
lpar = Leaf(token.LPAR, "")
|
lpar = Leaf(token.LPAR, "")
|
||||||
rpar = Leaf(token.RPAR, "")
|
rpar = Leaf(token.RPAR, "")
|
||||||
prefix = node.prefix
|
prefix = node.prefix
|
||||||
node.prefix = ""
|
node.prefix = ""
|
||||||
lpar.prefix = prefix
|
lpar.prefix = prefix
|
||||||
node.insert_child(0, lpar)
|
node.insert_child(0, lpar)
|
||||||
node.append_child(rpar)
|
node.append_child(rpar)
|
||||||
|
|
||||||
yield from self.visit_default(node)
|
yield from self.visit_default(node)
|
||||||
|
|
||||||
@ -292,9 +289,7 @@ 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 (
|
if is_stub_suite(node):
|
||||||
self.mode.is_pyi or Preview.dummy_implementations in self.mode
|
|
||||||
) and is_stub_suite(node, self.mode):
|
|
||||||
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)
|
||||||
@ -308,11 +303,7 @@ def visit_simple_stmt(self, node: Node) -> Iterator[Line]:
|
|||||||
prev_type = child.type
|
prev_type = child.type
|
||||||
|
|
||||||
if node.parent and node.parent.type in STATEMENT:
|
if node.parent and node.parent.type in STATEMENT:
|
||||||
if Preview.dummy_implementations in self.mode:
|
if is_parent_function_or_class(node) and is_stub_body(node):
|
||||||
condition = is_parent_function_or_class(node)
|
|
||||||
else:
|
|
||||||
condition = self.mode.is_pyi
|
|
||||||
if condition 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)
|
||||||
@ -320,11 +311,7 @@ def visit_simple_stmt(self, node: Node) -> Iterator[Line]:
|
|||||||
yield from self.line(-1)
|
yield from self.line(-1)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if (
|
if not node.parent or not is_stub_suite(node.parent):
|
||||||
not (self.mode.is_pyi or Preview.dummy_implementations in self.mode)
|
|
||||||
or not node.parent
|
|
||||||
or not is_stub_suite(node.parent, self.mode)
|
|
||||||
):
|
|
||||||
yield from self.line()
|
yield from self.line()
|
||||||
yield from self.visit_default(node)
|
yield from self.visit_default(node)
|
||||||
|
|
||||||
@ -342,11 +329,7 @@ def visit_async_stmt(self, node: Node) -> Iterator[Line]:
|
|||||||
break
|
break
|
||||||
|
|
||||||
internal_stmt = next(children)
|
internal_stmt = next(children)
|
||||||
if Preview.improved_async_statements_handling in self.mode:
|
yield from self.visit(internal_stmt)
|
||||||
yield from self.visit(internal_stmt)
|
|
||||||
else:
|
|
||||||
for child in internal_stmt.children:
|
|
||||||
yield from self.visit(child)
|
|
||||||
|
|
||||||
def visit_decorators(self, node: Node) -> Iterator[Line]:
|
def visit_decorators(self, node: Node) -> Iterator[Line]:
|
||||||
"""Visit decorators."""
|
"""Visit decorators."""
|
||||||
@ -420,10 +403,9 @@ def foo(a: int, b: float = 7): ...
|
|||||||
|
|
||||||
def foo(a: (int), b: (float) = 7): ...
|
def foo(a: (int), b: (float) = 7): ...
|
||||||
"""
|
"""
|
||||||
if Preview.parenthesize_long_type_hints in self.mode:
|
assert len(node.children) == 3
|
||||||
assert len(node.children) == 3
|
if maybe_make_parens_invisible_in_atom(node.children[2], parent=node):
|
||||||
if maybe_make_parens_invisible_in_atom(node.children[2], parent=node):
|
wrap_in_parentheses(node, node.children[2], visible=False)
|
||||||
wrap_in_parentheses(node, node.children[2], visible=False)
|
|
||||||
|
|
||||||
yield from self.visit_default(node)
|
yield from self.visit_default(node)
|
||||||
|
|
||||||
@ -529,13 +511,7 @@ def __post_init__(self) -> None:
|
|||||||
self.visit_with_stmt = partial(v, keywords={"with"}, parens={"with"})
|
self.visit_with_stmt = partial(v, keywords={"with"}, parens={"with"})
|
||||||
self.visit_classdef = partial(v, keywords={"class"}, parens=Ø)
|
self.visit_classdef = partial(v, keywords={"class"}, parens=Ø)
|
||||||
|
|
||||||
# When this is moved out of preview, add ":" directly to ASSIGNMENTS in nodes.py
|
self.visit_expr_stmt = partial(v, keywords=Ø, parens=ASSIGNMENTS)
|
||||||
if Preview.parenthesize_long_type_hints in self.mode:
|
|
||||||
assignments = ASSIGNMENTS | {":"}
|
|
||||||
else:
|
|
||||||
assignments = ASSIGNMENTS
|
|
||||||
self.visit_expr_stmt = partial(v, keywords=Ø, parens=assignments)
|
|
||||||
|
|
||||||
self.visit_return_stmt = partial(v, keywords={"return"}, parens={"return"})
|
self.visit_return_stmt = partial(v, keywords={"return"}, parens={"return"})
|
||||||
self.visit_import_from = partial(v, keywords=Ø, parens={"import"})
|
self.visit_import_from = partial(v, keywords=Ø, parens={"import"})
|
||||||
self.visit_del_stmt = partial(v, keywords=Ø, parens={"del"})
|
self.visit_del_stmt = partial(v, keywords=Ø, parens={"del"})
|
||||||
@ -576,9 +552,7 @@ def transform_line(
|
|||||||
# We need the line string when power operators are hugging to determine if we should
|
# We need the line string when power operators are hugging to determine if we should
|
||||||
# split the line. Default to line_str, if no power operator are present on the line.
|
# split the line. Default to line_str, if no power operator are present on the line.
|
||||||
line_str_hugging_power_ops = (
|
line_str_hugging_power_ops = (
|
||||||
(_hugging_power_ops_line_to_string(line, features, mode) or line_str)
|
_hugging_power_ops_line_to_string(line, features, mode) or line_str
|
||||||
if Preview.fix_power_op_line_length in mode
|
|
||||||
else line_str
|
|
||||||
)
|
)
|
||||||
|
|
||||||
ll = mode.line_length
|
ll = mode.line_length
|
||||||
@ -688,9 +662,6 @@ def should_split_funcdef_with_rhs(line: Line, mode: Mode) -> bool:
|
|||||||
"""If a funcdef has a magic trailing comma in the return type, then we should first
|
"""If a funcdef has a magic trailing comma in the return type, then we should first
|
||||||
split the line with rhs to respect the comma.
|
split the line with rhs to respect the comma.
|
||||||
"""
|
"""
|
||||||
if Preview.respect_magic_trailing_comma_in_return_type not in mode:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return_type_leaves: List[Leaf] = []
|
return_type_leaves: List[Leaf] = []
|
||||||
in_return_type = False
|
in_return_type = False
|
||||||
|
|
||||||
@ -919,9 +890,6 @@ def _maybe_split_omitting_optional_parens(
|
|||||||
try:
|
try:
|
||||||
# The RHSResult Omitting Optional Parens.
|
# The RHSResult Omitting Optional Parens.
|
||||||
rhs_oop = _first_right_hand_split(line, omit=omit)
|
rhs_oop = _first_right_hand_split(line, omit=omit)
|
||||||
prefer_splitting_rhs_mode = (
|
|
||||||
Preview.prefer_splitting_right_hand_side_of_assignments in line.mode
|
|
||||||
)
|
|
||||||
is_split_right_after_equal = (
|
is_split_right_after_equal = (
|
||||||
len(rhs.head.leaves) >= 2 and rhs.head.leaves[-2].type == token.EQUAL
|
len(rhs.head.leaves) >= 2 and rhs.head.leaves[-2].type == token.EQUAL
|
||||||
)
|
)
|
||||||
@ -937,8 +905,7 @@ def _maybe_split_omitting_optional_parens(
|
|||||||
)
|
)
|
||||||
if (
|
if (
|
||||||
not (
|
not (
|
||||||
prefer_splitting_rhs_mode
|
is_split_right_after_equal
|
||||||
and is_split_right_after_equal
|
|
||||||
and rhs_head_contains_brackets
|
and rhs_head_contains_brackets
|
||||||
and rhs_head_short_enough
|
and rhs_head_short_enough
|
||||||
and rhs_head_explode_blocked_by_magic_trailing_comma
|
and rhs_head_explode_blocked_by_magic_trailing_comma
|
||||||
@ -1224,11 +1191,7 @@ def append_to_line(leaf: Leaf) -> Iterator[Line]:
|
|||||||
trailing_comma_safe and Feature.TRAILING_COMMA_IN_CALL in features
|
trailing_comma_safe and Feature.TRAILING_COMMA_IN_CALL in features
|
||||||
)
|
)
|
||||||
|
|
||||||
if (
|
if last_leaf.type == STANDALONE_COMMENT and leaf_idx == last_non_comment_leaf:
|
||||||
Preview.add_trailing_comma_consistently in mode
|
|
||||||
and last_leaf.type == STANDALONE_COMMENT
|
|
||||||
and leaf_idx == last_non_comment_leaf
|
|
||||||
):
|
|
||||||
current_line = _safe_add_trailing_comma(
|
current_line = _safe_add_trailing_comma(
|
||||||
trailing_comma_safe, delimiter_priority, current_line
|
trailing_comma_safe, delimiter_priority, current_line
|
||||||
)
|
)
|
||||||
@ -1315,11 +1278,7 @@ def normalize_invisible_parens( # noqa: C901
|
|||||||
|
|
||||||
# Fixes a bug where invisible parens are not properly wrapped around
|
# Fixes a bug where invisible parens are not properly wrapped around
|
||||||
# case blocks.
|
# case blocks.
|
||||||
if (
|
if isinstance(child, Node) and child.type == syms.case_block:
|
||||||
isinstance(child, Node)
|
|
||||||
and child.type == syms.case_block
|
|
||||||
and Preview.long_case_block_line_splitting in mode
|
|
||||||
):
|
|
||||||
normalize_invisible_parens(
|
normalize_invisible_parens(
|
||||||
child, parens_after={"case"}, mode=mode, features=features
|
child, parens_after={"case"}, mode=mode, features=features
|
||||||
)
|
)
|
||||||
@ -1374,7 +1333,6 @@ def normalize_invisible_parens( # noqa: C901
|
|||||||
and child.next_sibling is not None
|
and child.next_sibling is not None
|
||||||
and child.next_sibling.type == token.COLON
|
and child.next_sibling.type == token.COLON
|
||||||
and child.value == "case"
|
and child.value == "case"
|
||||||
and Preview.long_case_block_line_splitting in mode
|
|
||||||
):
|
):
|
||||||
# A special patch for "case case:" scenario, the second occurrence
|
# A special patch for "case case:" scenario, the second occurrence
|
||||||
# of case will be not parsed as a Python keyword.
|
# of case will be not parsed as a Python keyword.
|
||||||
@ -1448,7 +1406,6 @@ def _maybe_wrap_cms_in_parens(
|
|||||||
"""
|
"""
|
||||||
if (
|
if (
|
||||||
Feature.PARENTHESIZED_CONTEXT_MANAGERS not in features
|
Feature.PARENTHESIZED_CONTEXT_MANAGERS not in features
|
||||||
or Preview.wrap_multiple_context_managers_in_parens not in mode
|
|
||||||
or len(node.children) <= 2
|
or len(node.children) <= 2
|
||||||
# If it's an atom, it's already wrapped in parens.
|
# If it's an atom, it's already wrapped in parens.
|
||||||
or node.children[1].type == syms.atom
|
or node.children[1].type == syms.atom
|
||||||
|
@ -202,9 +202,7 @@ def _is_triple_quoted_string(self) -> bool:
|
|||||||
value = self.leaves[0].value
|
value = self.leaves[0].value
|
||||||
if value.startswith(('"""', "'''")):
|
if value.startswith(('"""', "'''")):
|
||||||
return True
|
return True
|
||||||
if Preview.accept_raw_docstrings in self.mode and value.startswith(
|
if value.startswith(("r'''", 'r"""', "R'''", 'R"""')):
|
||||||
("r'''", 'r"""', "R'''", 'R"""')
|
|
||||||
):
|
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -450,14 +448,8 @@ def is_complex_subscript(self, leaf: Leaf) -> bool:
|
|||||||
if subscript_start.type == syms.subscriptlist:
|
if subscript_start.type == syms.subscriptlist:
|
||||||
subscript_start = child_towards(subscript_start, leaf)
|
subscript_start = child_towards(subscript_start, leaf)
|
||||||
|
|
||||||
# When this is moved out of preview, add syms.namedexpr_test directly to
|
|
||||||
# TEST_DESCENDANTS in nodes.py
|
|
||||||
if Preview.walrus_subscript in self.mode:
|
|
||||||
test_decendants = TEST_DESCENDANTS | {syms.namedexpr_test}
|
|
||||||
else:
|
|
||||||
test_decendants = TEST_DESCENDANTS
|
|
||||||
return subscript_start is not None and any(
|
return subscript_start is not None and any(
|
||||||
n.type in test_decendants for n in subscript_start.pre_order()
|
n.type in TEST_DESCENDANTS for n in subscript_start.pre_order()
|
||||||
)
|
)
|
||||||
|
|
||||||
def enumerate_with_length(
|
def enumerate_with_length(
|
||||||
@ -567,8 +559,7 @@ def maybe_empty_lines(self, current_line: Line) -> LinesBlock:
|
|||||||
lines (two on module-level).
|
lines (two on module-level).
|
||||||
"""
|
"""
|
||||||
form_feed = (
|
form_feed = (
|
||||||
Preview.allow_form_feeds in self.mode
|
current_line.depth == 0
|
||||||
and current_line.depth == 0
|
|
||||||
and bool(current_line.leaves)
|
and bool(current_line.leaves)
|
||||||
and "\f\n" in current_line.leaves[0].prefix
|
and "\f\n" in current_line.leaves[0].prefix
|
||||||
)
|
)
|
||||||
@ -582,8 +573,7 @@ def maybe_empty_lines(self, current_line: Line) -> LinesBlock:
|
|||||||
else before - previous_after
|
else before - previous_after
|
||||||
)
|
)
|
||||||
if (
|
if (
|
||||||
Preview.module_docstring_newlines in current_line.mode
|
self.previous_block
|
||||||
and self.previous_block
|
|
||||||
and self.previous_block.previous_block is None
|
and self.previous_block.previous_block is None
|
||||||
and len(self.previous_block.original_line.leaves) == 1
|
and len(self.previous_block.original_line.leaves) == 1
|
||||||
and self.previous_block.original_line.is_docstring
|
and self.previous_block.original_line.is_docstring
|
||||||
@ -640,11 +630,7 @@ def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
|
|||||||
if previous_def is not None:
|
if previous_def is not None:
|
||||||
assert self.previous_line is not None
|
assert self.previous_line is not None
|
||||||
if self.mode.is_pyi:
|
if self.mode.is_pyi:
|
||||||
if (
|
if previous_def.is_class and not previous_def.is_stub_class:
|
||||||
Preview.blank_line_after_nested_stub_class in self.mode
|
|
||||||
and previous_def.is_class
|
|
||||||
and not previous_def.is_stub_class
|
|
||||||
):
|
|
||||||
before = 1
|
before = 1
|
||||||
elif depth and not current_line.is_def and self.previous_line.is_def:
|
elif 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.
|
||||||
@ -695,18 +681,12 @@ def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
|
|||||||
and self.previous_line.is_class
|
and self.previous_line.is_class
|
||||||
and current_line.is_docstring
|
and current_line.is_docstring
|
||||||
):
|
):
|
||||||
if Preview.no_blank_line_before_class_docstring in current_line.mode:
|
return 0, 1
|
||||||
return 0, 1
|
|
||||||
return before, 1
|
|
||||||
|
|
||||||
# In preview mode, always allow blank lines, except right before a function
|
# In preview mode, always allow blank lines, except right before a function
|
||||||
# docstring
|
# docstring
|
||||||
is_empty_first_line_ok = (
|
is_empty_first_line_ok = not current_line.is_docstring or (
|
||||||
Preview.allow_empty_first_line_in_block in current_line.mode
|
self.previous_line and not self.previous_line.is_def
|
||||||
and (
|
|
||||||
not current_line.is_docstring
|
|
||||||
or (self.previous_line and not self.previous_line.is_def)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -736,7 +716,7 @@ def _maybe_empty_lines_for_class_or_def( # noqa: C901
|
|||||||
if self.previous_line.depth < current_line.depth and (
|
if self.previous_line.depth < current_line.depth and (
|
||||||
self.previous_line.is_class or self.previous_line.is_def
|
self.previous_line.is_class or self.previous_line.is_def
|
||||||
):
|
):
|
||||||
if self.mode.is_pyi or not Preview.allow_empty_first_line_in_block:
|
if self.mode.is_pyi:
|
||||||
return 0, 0
|
return 0, 0
|
||||||
else:
|
else:
|
||||||
return 1 if user_had_newline else 0, 0
|
return 1 if user_had_newline else 0, 0
|
||||||
@ -776,10 +756,7 @@ def _maybe_empty_lines_for_class_or_def( # noqa: C901
|
|||||||
# Don't inspect the previous line if it's part of the body of the previous
|
# Don't inspect the previous line if it's part of the body of the previous
|
||||||
# statement in the same level, we always want a blank line if there's
|
# statement in the same level, we always want a blank line if there's
|
||||||
# something with a body preceding.
|
# something with a body preceding.
|
||||||
elif (
|
elif self.previous_line.depth > current_line.depth:
|
||||||
Preview.blank_line_between_nested_and_def_stub_file in current_line.mode
|
|
||||||
and self.previous_line.depth > current_line.depth
|
|
||||||
):
|
|
||||||
newlines = 1
|
newlines = 1
|
||||||
elif (
|
elif (
|
||||||
current_line.is_def or current_line.is_decorator
|
current_line.is_def or current_line.is_decorator
|
||||||
@ -800,11 +777,7 @@ def _maybe_empty_lines_for_class_or_def( # noqa: C901
|
|||||||
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
|
# 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.
|
# new lines. This is useful for instance for @overload or Protocols.
|
||||||
if (
|
if self.previous_line.is_stub_def and not user_had_newline:
|
||||||
Preview.dummy_implementations in self.mode
|
|
||||||
and self.previous_line.is_stub_def
|
|
||||||
and not user_had_newline
|
|
||||||
):
|
|
||||||
newlines = 0
|
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
|
||||||
@ -859,11 +832,9 @@ def is_line_short_enough( # noqa: C901
|
|||||||
if not line_str:
|
if not line_str:
|
||||||
line_str = line_to_string(line)
|
line_str = line_to_string(line)
|
||||||
|
|
||||||
width = str_width if Preview.respect_east_asian_width in mode else len
|
|
||||||
|
|
||||||
if Preview.multiline_string_handling not in mode:
|
if Preview.multiline_string_handling not in mode:
|
||||||
return (
|
return (
|
||||||
width(line_str) <= mode.line_length
|
str_width(line_str) <= mode.line_length
|
||||||
and "\n" not in line_str # multiline strings
|
and "\n" not in line_str # multiline strings
|
||||||
and not line.contains_standalone_comments()
|
and not line.contains_standalone_comments()
|
||||||
)
|
)
|
||||||
@ -872,10 +843,10 @@ def is_line_short_enough( # noqa: C901
|
|||||||
return False
|
return False
|
||||||
if "\n" not in line_str:
|
if "\n" not in line_str:
|
||||||
# No multiline strings (MLS) present
|
# No multiline strings (MLS) present
|
||||||
return width(line_str) <= mode.line_length
|
return str_width(line_str) <= mode.line_length
|
||||||
|
|
||||||
first, *_, last = line_str.split("\n")
|
first, *_, last = line_str.split("\n")
|
||||||
if width(first) > mode.line_length or width(last) > mode.line_length:
|
if str_width(first) > mode.line_length or str_width(last) > mode.line_length:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Traverse the AST to examine the context of the multiline string (MLS),
|
# Traverse the AST to examine the context of the multiline string (MLS),
|
||||||
@ -1015,11 +986,7 @@ def can_omit_invisible_parens(
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
if delimiter_count == 1:
|
if delimiter_count == 1:
|
||||||
if (
|
if max_priority == COMMA_PRIORITY and rhs.head.is_with_or_async_with_stmt:
|
||||||
Preview.wrap_multiple_context_managers_in_parens in line.mode
|
|
||||||
and max_priority == COMMA_PRIORITY
|
|
||||||
and rhs.head.is_with_or_async_with_stmt
|
|
||||||
):
|
|
||||||
# For two context manager with statements, the optional parentheses read
|
# For two context manager with statements, the optional parentheses read
|
||||||
# better. In this case, `rhs.body` is the context managers part of
|
# better. In this case, `rhs.body` is the context managers part of
|
||||||
# the with statement. `rhs.head` is the `with (` part on the previous
|
# the with statement. `rhs.head` is the `with (` part on the previous
|
||||||
|
@ -168,35 +168,14 @@ def supports_feature(target_versions: Set[TargetVersion], feature: Feature) -> b
|
|||||||
class Preview(Enum):
|
class Preview(Enum):
|
||||||
"""Individual preview style features."""
|
"""Individual preview style features."""
|
||||||
|
|
||||||
add_trailing_comma_consistently = auto()
|
|
||||||
blank_line_after_nested_stub_class = auto()
|
|
||||||
blank_line_between_nested_and_def_stub_file = auto()
|
|
||||||
hex_codes_in_unicode_sequences = auto()
|
hex_codes_in_unicode_sequences = auto()
|
||||||
improved_async_statements_handling = auto()
|
|
||||||
multiline_string_handling = auto()
|
|
||||||
no_blank_line_before_class_docstring = auto()
|
|
||||||
prefer_splitting_right_hand_side_of_assignments = auto()
|
|
||||||
# NOTE: string_processing requires wrap_long_dict_values_in_parens
|
# NOTE: string_processing requires wrap_long_dict_values_in_parens
|
||||||
# for https://github.com/psf/black/issues/3117 to be fixed.
|
# for https://github.com/psf/black/issues/3117 to be fixed.
|
||||||
string_processing = auto()
|
string_processing = auto()
|
||||||
parenthesize_conditional_expressions = auto()
|
|
||||||
parenthesize_long_type_hints = auto()
|
|
||||||
respect_magic_trailing_comma_in_return_type = auto()
|
|
||||||
skip_magic_trailing_comma_in_subscript = auto()
|
|
||||||
wrap_long_dict_values_in_parens = auto()
|
|
||||||
wrap_multiple_context_managers_in_parens = auto()
|
|
||||||
dummy_implementations = auto()
|
|
||||||
walrus_subscript = auto()
|
|
||||||
module_docstring_newlines = auto()
|
|
||||||
accept_raw_docstrings = auto()
|
|
||||||
fix_power_op_line_length = auto()
|
|
||||||
hug_parens_with_braces_and_square_brackets = auto()
|
hug_parens_with_braces_and_square_brackets = auto()
|
||||||
allow_empty_first_line_in_block = auto()
|
|
||||||
single_line_format_skip_with_multiple_comments = auto()
|
|
||||||
long_case_block_line_splitting = auto()
|
|
||||||
allow_form_feeds = auto()
|
|
||||||
unify_docstring_detection = auto()
|
unify_docstring_detection = auto()
|
||||||
respect_east_asian_width = auto()
|
wrap_long_dict_values_in_parens = auto()
|
||||||
|
multiline_string_handling = auto()
|
||||||
|
|
||||||
|
|
||||||
class Deprecated(UserWarning):
|
class Deprecated(UserWarning):
|
||||||
|
@ -104,6 +104,7 @@
|
|||||||
syms.trailer,
|
syms.trailer,
|
||||||
syms.term,
|
syms.term,
|
||||||
syms.power,
|
syms.power,
|
||||||
|
syms.namedexpr_test,
|
||||||
}
|
}
|
||||||
TYPED_NAMES: Final = {syms.tname, syms.tname_star}
|
TYPED_NAMES: Final = {syms.tname, syms.tname_star}
|
||||||
ASSIGNMENTS: Final = {
|
ASSIGNMENTS: Final = {
|
||||||
@ -121,6 +122,7 @@
|
|||||||
">>=",
|
">>=",
|
||||||
"**=",
|
"**=",
|
||||||
"//=",
|
"//=",
|
||||||
|
":",
|
||||||
}
|
}
|
||||||
|
|
||||||
IMPLICIT_TUPLE: Final = {syms.testlist, syms.testlist_star_expr, syms.exprlist}
|
IMPLICIT_TUPLE: Final = {syms.testlist, syms.testlist_star_expr, syms.exprlist}
|
||||||
@ -346,9 +348,7 @@ def whitespace(leaf: Leaf, *, complex_subscript: bool, mode: Mode) -> str: # no
|
|||||||
|
|
||||||
return NO
|
return NO
|
||||||
|
|
||||||
elif Preview.walrus_subscript in mode and (
|
elif t == token.COLONEQUAL or prev.type == token.COLONEQUAL:
|
||||||
t == token.COLONEQUAL or prev.type == token.COLONEQUAL
|
|
||||||
):
|
|
||||||
return SPACE
|
return SPACE
|
||||||
|
|
||||||
elif not complex_subscript:
|
elif not complex_subscript:
|
||||||
@ -753,13 +753,9 @@ def is_function_or_class(node: Node) -> bool:
|
|||||||
return node.type in {syms.funcdef, syms.classdef, syms.async_funcdef}
|
return node.type in {syms.funcdef, syms.classdef, syms.async_funcdef}
|
||||||
|
|
||||||
|
|
||||||
def is_stub_suite(node: Node, mode: Mode) -> bool:
|
def is_stub_suite(node: Node) -> bool:
|
||||||
"""Return True if `node` is a suite with a stub body."""
|
"""Return True if `node` is a suite with a stub body."""
|
||||||
if (
|
if node.parent is not None and not is_parent_function_or_class(node):
|
||||||
node.parent is not None
|
|
||||||
and Preview.dummy_implementations in mode
|
|
||||||
and not is_parent_function_or_class(node)
|
|
||||||
):
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# If there is a comment, we want to keep it.
|
# If there is a comment, we want to keep it.
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# flags: --preview
|
|
||||||
def foo():
|
def foo():
|
||||||
"""
|
"""
|
||||||
Docstring
|
Docstring
|
@ -1,4 +1,3 @@
|
|||||||
# flags: --preview
|
|
||||||
async def func() -> (int):
|
async def func() -> (int):
|
||||||
return 0
|
return 0
|
||||||
|
|
@ -45,8 +45,7 @@ def wat():
|
|||||||
@deco2(with_args=True)
|
@deco2(with_args=True)
|
||||||
# leading 3
|
# leading 3
|
||||||
@deco3
|
@deco3
|
||||||
def decorated1():
|
def decorated1(): ...
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
# leading 1
|
# leading 1
|
||||||
@ -54,8 +53,7 @@ def decorated1():
|
|||||||
# leading 2
|
# leading 2
|
||||||
@deco2(with_args=True)
|
@deco2(with_args=True)
|
||||||
# leading function comment
|
# leading function comment
|
||||||
def decorated1():
|
def decorated1(): ...
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
# Note: this is fixed in
|
# Note: this is fixed in
|
||||||
@ -65,8 +63,7 @@ def decorated1():
|
|||||||
|
|
||||||
|
|
||||||
# This comment should be split from `some_instruction` by two lines but isn't.
|
# This comment should be split from `some_instruction` by two lines but isn't.
|
||||||
def g():
|
def g(): ...
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# flags: --preview
|
|
||||||
long_kwargs_single_line = my_function(
|
long_kwargs_single_line = my_function(
|
||||||
foo="test, this is a sample value",
|
foo="test, this is a sample value",
|
||||||
bar=some_long_value_name_foo_bar_baz if some_boolean_variable else some_fallback_value_foo_bar_baz,
|
bar=some_long_value_name_foo_bar_baz if some_boolean_variable else some_fallback_value_foo_bar_baz,
|
||||||
@ -197,7 +196,9 @@ def foo(wait: bool = True):
|
|||||||
time.sleep(1) if wait else None
|
time.sleep(1) if wait else None
|
||||||
|
|
||||||
|
|
||||||
a = "".join((
|
a = "".join(
|
||||||
"", # comment
|
(
|
||||||
"" if True else "",
|
"", # comment
|
||||||
))
|
"" if True else "",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# flags: --preview --minimum-version=3.8
|
# flags: --minimum-version=3.8
|
||||||
with \
|
with \
|
||||||
make_context_manager1() as cm1, \
|
make_context_manager1() as cm1, \
|
||||||
make_context_manager2() as cm2, \
|
make_context_manager2() as cm2, \
|
@ -1,4 +1,4 @@
|
|||||||
# flags: --preview --minimum-version=3.9
|
# flags: --minimum-version=3.9
|
||||||
with \
|
with \
|
||||||
make_context_manager1() as cm1, \
|
make_context_manager1() as cm1, \
|
||||||
make_context_manager2() as cm2, \
|
make_context_manager2() as cm2, \
|
@ -1,4 +1,4 @@
|
|||||||
# flags: --preview --minimum-version=3.10
|
# flags: --minimum-version=3.10
|
||||||
# This file uses pattern matching introduced in Python 3.10.
|
# This file uses pattern matching introduced in Python 3.10.
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
# flags: --preview --minimum-version=3.11
|
# flags: --minimum-version=3.11
|
||||||
# This file uses except* clause in Python 3.11.
|
# This file uses except* clause in Python 3.11.
|
||||||
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
|||||||
# flags: --preview
|
|
||||||
# This file doesn't use any Python 3.9+ only grammars.
|
# This file doesn't use any Python 3.9+ only grammars.
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
# flags: --preview --minimum-version=3.9
|
# flags: --minimum-version=3.9
|
||||||
# This file uses parenthesized context managers introduced in Python 3.9.
|
# This file uses parenthesized context managers introduced in Python 3.9.
|
||||||
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
|||||||
# flags: --preview
|
|
||||||
from typing import NoReturn, Protocol, Union, overload
|
from typing import NoReturn, Protocol, Union, overload
|
||||||
|
|
||||||
class Empty:
|
class Empty:
|
@ -119,6 +119,7 @@ def f():
|
|||||||
if not prev:
|
if not prev:
|
||||||
prevp = preceding_leaf(p)
|
prevp = preceding_leaf(p)
|
||||||
if not prevp or prevp.type in OPENING_BRACKETS:
|
if not prevp or prevp.type in OPENING_BRACKETS:
|
||||||
|
|
||||||
return NO
|
return NO
|
||||||
|
|
||||||
if prevp.type == token.EQUAL:
|
if prevp.type == token.EQUAL:
|
||||||
|
@ -243,12 +243,8 @@ def spaces_types(
|
|||||||
g: int = 1 if False else 2,
|
g: int = 1 if False else 2,
|
||||||
h: str = "",
|
h: str = "",
|
||||||
i: str = r"",
|
i: str = r"",
|
||||||
):
|
): ...
|
||||||
...
|
def spaces2(result=_core.Value(None)): ...
|
||||||
|
|
||||||
|
|
||||||
def spaces2(result=_core.Value(None)):
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
something = {
|
something = {
|
||||||
|
@ -161,8 +161,7 @@ def this_wont_be_formatted ( self ) -> str: ...
|
|||||||
|
|
||||||
|
|
||||||
class Factory(t.Protocol):
|
class Factory(t.Protocol):
|
||||||
def this_will_be_formatted(self, **kwargs) -> Named:
|
def this_will_be_formatted(self, **kwargs) -> Named: ...
|
||||||
...
|
|
||||||
|
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# flags: --preview
|
|
||||||
|
|
||||||
|
|
||||||
# Warning! This file contains form feeds (ASCII 0x0C, often represented by \f or ^L).
|
# Warning! This file contains form feeds (ASCII 0x0C, often represented by \f or ^L).
|
@ -158,10 +158,7 @@ def spaces_types(
|
|||||||
g: int = 1 if False else 2,
|
g: int = 1 if False else 2,
|
||||||
h: str = "",
|
h: str = "",
|
||||||
i: str = r"",
|
i: str = r"",
|
||||||
):
|
): ...
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
def spaces2(result=_core.Value(None)):
|
def spaces2(result=_core.Value(None)):
|
||||||
assert fut is self._read_fut, (fut, self._read_fut)
|
assert fut is self._read_fut, (fut, self._read_fut)
|
||||||
|
|
||||||
|
@ -21,15 +21,21 @@ def http_status(status):
|
|||||||
|
|
||||||
# output
|
# output
|
||||||
def http_status(status):
|
def http_status(status):
|
||||||
|
|
||||||
match status:
|
match status:
|
||||||
|
|
||||||
case 400:
|
case 400:
|
||||||
|
|
||||||
return "Bad request"
|
return "Bad request"
|
||||||
|
|
||||||
case 401:
|
case 401:
|
||||||
|
|
||||||
return "Unauthorized"
|
return "Unauthorized"
|
||||||
|
|
||||||
case 403:
|
case 403:
|
||||||
|
|
||||||
return "Forbidden"
|
return "Forbidden"
|
||||||
|
|
||||||
case 404:
|
case 404:
|
||||||
|
|
||||||
return "Not found"
|
return "Not found"
|
@ -43,8 +43,10 @@
|
|||||||
% (
|
% (
|
||||||
"formatted",
|
"formatted",
|
||||||
"string",
|
"string",
|
||||||
): "This is a really really really long string that has to go inside of a dictionary. It is %s bad (#%d)."
|
): (
|
||||||
% ("soooo", 2),
|
"This is a really really really long string that has to go inside of a dictionary. It is %s bad (#%d)."
|
||||||
|
% ("soooo", 2)
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
func_with_keywords(
|
func_with_keywords(
|
||||||
@ -254,10 +256,12 @@
|
|||||||
+ CONCATENATED
|
+ CONCATENATED
|
||||||
+ "using the '+' operator."
|
+ "using the '+' operator."
|
||||||
)
|
)
|
||||||
annotated_variable: Final = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped."
|
annotated_variable: Final = (
|
||||||
annotated_variable: Literal[
|
"This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped."
|
||||||
"fakse_literal"
|
)
|
||||||
] = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped."
|
annotated_variable: Literal["fakse_literal"] = (
|
||||||
|
"This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped."
|
||||||
|
)
|
||||||
|
|
||||||
backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\"
|
backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\"
|
||||||
backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\\\"
|
backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\\\"
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# flags: --preview
|
|
||||||
"""Single line module-level docstring should be followed by single newline."""
|
"""Single line module-level docstring should be followed by single newline."""
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# flags: --preview
|
# flags: --preview
|
||||||
"""I am a very helpful module docstring.
|
"""I am a very helpful module docstring.
|
||||||
|
|
||||||
With trailing spaces:
|
With trailing spaces (only removed with unify_docstring_detection on):
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
|
||||||
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||||
Ut enim ad minim veniam,
|
Ut enim ad minim veniam,
|
||||||
@ -39,7 +39,7 @@
|
|||||||
# output
|
# output
|
||||||
"""I am a very helpful module docstring.
|
"""I am a very helpful module docstring.
|
||||||
|
|
||||||
With trailing spaces:
|
With trailing spaces (only removed with unify_docstring_detection on):
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
|
||||||
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||||
Ut enim ad minim veniam,
|
Ut enim ad minim veniam,
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# flags: --preview
|
|
||||||
"""Single line module-level docstring should be followed by single newline."""
|
"""Single line module-level docstring should be followed by single newline."""
|
||||||
a = 1
|
a = 1
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# flags: --preview
|
|
||||||
"""Single line module-level docstring should be followed by single newline."""
|
"""Single line module-level docstring should be followed by single newline."""
|
||||||
|
|
||||||
a = 1
|
a = 1
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# flags: --preview
|
|
||||||
"""Two blank lines between module docstring and a class."""
|
"""Two blank lines between module docstring and a class."""
|
||||||
class MyClass:
|
class MyClass:
|
||||||
pass
|
pass
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# flags: --preview
|
|
||||||
"""Two blank lines between module docstring and a function def."""
|
"""Two blank lines between module docstring and a function def."""
|
||||||
def function():
|
def function():
|
||||||
pass
|
pass
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# flags: --pyi --preview
|
# flags: --pyi
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
class Outer:
|
class Outer:
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# flags: --preview
|
|
||||||
def line_before_docstring():
|
def line_before_docstring():
|
||||||
|
|
||||||
"""Please move me up"""
|
"""Please move me up"""
|
||||||
@ -63,4 +62,5 @@ class MultilineDocstringsAsWell:
|
|||||||
|
|
||||||
|
|
||||||
class SingleQuotedDocstring:
|
class SingleQuotedDocstring:
|
||||||
|
|
||||||
"I'm a docstring but I don't even get triple quotes."
|
"I'm a docstring but I don't even get triple quotes."
|
@ -1,4 +1,4 @@
|
|||||||
# flags: --preview --minimum-version=3.10
|
# flags: --minimum-version=3.10
|
||||||
match x:
|
match x:
|
||||||
case "abcd" | "abcd" | "abcd" :
|
case "abcd" | "abcd" | "abcd" :
|
||||||
pass
|
pass
|
@ -1,4 +1,4 @@
|
|||||||
# flags: --preview --minimum-version=3.10
|
# flags: --minimum-version=3.10
|
||||||
match maybe, multiple:
|
match maybe, multiple:
|
||||||
case perhaps, 5:
|
case perhaps, 5:
|
||||||
pass
|
pass
|
@ -1,4 +1,4 @@
|
|||||||
# flags: --preview --minimum-version=3.10
|
# flags: --minimum-version=3.10
|
||||||
# This has always worked
|
# This has always worked
|
||||||
z= Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong
|
z= Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
# flags: --minimum-version=3.10
|
# flags: --minimum-version=3.10
|
||||||
# Unparenthesized walruses are now allowed in indices since Python 3.10.
|
# Unparenthesized walruses are now allowed in indices since Python 3.10.
|
||||||
x[a:=0]
|
x[a := 0]
|
||||||
x[a:=0, b:=1]
|
x[a := 0, b := 1]
|
||||||
x[5, b:=0]
|
x[5, b := 0]
|
||||||
|
|
||||||
# Walruses are allowed inside generator expressions on function calls since 3.10.
|
# Walruses are allowed inside generator expressions on function calls since 3.10.
|
||||||
if any(match := pattern_error.match(s) for s in buffer):
|
if any(match := pattern_error.match(s) for s in buffer):
|
||||||
|
@ -96,18 +96,16 @@ async def await_the_walrus():
|
|||||||
foo(x=(y := f(x)))
|
foo(x=(y := f(x)))
|
||||||
|
|
||||||
|
|
||||||
def foo(answer=(p := 42)):
|
def foo(answer=(p := 42)): ...
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
def foo2(answer: (p := 42) = 5):
|
def foo2(answer: (p := 42) = 5): ...
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
lambda: (x := 1)
|
lambda: (x := 1)
|
||||||
|
|
||||||
a[(x := 12)]
|
a[(x := 12)]
|
||||||
a[:(x := 13)]
|
a[: (x := 13)]
|
||||||
|
|
||||||
# we don't touch expressions in f-strings but if we do one day, don't break 'em
|
# we don't touch expressions in f-strings but if we do one day, don't break 'em
|
||||||
f"{(x:=10)}"
|
f"{(x:=10)}"
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# flags: --preview
|
|
||||||
x[(a:=0):]
|
x[(a:=0):]
|
||||||
x[:(a:=0)]
|
x[:(a:=0)]
|
||||||
|
|
@ -1,4 +1,3 @@
|
|||||||
# flags: --preview
|
|
||||||
("" % a) ** 2
|
("" % a) ** 2
|
||||||
("" % a)[0]
|
("" % a)[0]
|
||||||
("" % a)()
|
("" % a)()
|
||||||
@ -31,9 +30,9 @@
|
|||||||
2 // ("" % a)
|
2 // ("" % a)
|
||||||
2 % ("" % a)
|
2 % ("" % a)
|
||||||
+("" % a)
|
+("" % a)
|
||||||
b + "" % a
|
b + ("" % a)
|
||||||
-("" % a)
|
-("" % a)
|
||||||
b - "" % a
|
b - ("" % a)
|
||||||
b + -("" % a)
|
b + -("" % a)
|
||||||
~("" % a)
|
~("" % a)
|
||||||
2 ** ("" % a)
|
2 ** ("" % a)
|
@ -1,4 +1,3 @@
|
|||||||
# flags: --preview
|
|
||||||
a = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1
|
a = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1
|
||||||
b = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1
|
b = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1
|
||||||
c = 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1
|
c = 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1
|
@ -1,4 +1,3 @@
|
|||||||
# flags: --preview
|
|
||||||
first_item, second_item = (
|
first_item, second_item = (
|
||||||
some_looooooooong_module.some_looooooooooooooong_function_name(
|
some_looooooooong_module.some_looooooooooooooong_function_name(
|
||||||
first_argument, second_argument, third_argument
|
first_argument, second_argument, third_argument
|
@ -1,4 +1,4 @@
|
|||||||
# flags: --preview --minimum-version=3.10
|
# flags: --minimum-version=3.10
|
||||||
x[a:=0]
|
x[a:=0]
|
||||||
x[a := 0]
|
x[a := 0]
|
||||||
x[a := 0, b := 1]
|
x[a := 0, b := 1]
|
||||||
|
@ -15,19 +15,16 @@ def f():
|
|||||||
# output
|
# output
|
||||||
|
|
||||||
@relaxed_decorator[0]
|
@relaxed_decorator[0]
|
||||||
def f():
|
def f(): ...
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
@relaxed_decorator[
|
@relaxed_decorator[
|
||||||
extremely_long_name_that_definitely_will_not_fit_on_one_line_of_standard_length
|
extremely_long_name_that_definitely_will_not_fit_on_one_line_of_standard_length
|
||||||
]
|
]
|
||||||
def f():
|
def f(): ...
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
@extremely_long_variable_name_that_doesnt_fit := complex.expression(
|
@extremely_long_variable_name_that_doesnt_fit := complex.expression(
|
||||||
with_long="arguments_value_that_wont_fit_at_the_end_of_the_line"
|
with_long="arguments_value_that_wont_fit_at_the_end_of_the_line"
|
||||||
)
|
)
|
||||||
def f():
|
def f(): ...
|
||||||
...
|
|
@ -1,4 +1,4 @@
|
|||||||
# flags: --preview --skip-string-normalization
|
# flags: --skip-string-normalization
|
||||||
class C:
|
class C:
|
||||||
|
|
||||||
r"""Raw"""
|
r"""Raw"""
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# flags: --preview --skip-string-normalization
|
# flags: --skip-string-normalization
|
||||||
def do_not_touch_this_prefix():
|
def do_not_touch_this_prefix():
|
||||||
R"""There was a bug where docstring prefixes would be normalized even with -S."""
|
R"""There was a bug where docstring prefixes would be normalized even with -S."""
|
||||||
|
|
@ -3,14 +3,14 @@
|
|||||||
|
|
||||||
def foo1():
|
def foo1():
|
||||||
|
|
||||||
print("The newline above me should be deleted!")
|
print("The newline above me should be kept!")
|
||||||
|
|
||||||
|
|
||||||
def foo2():
|
def foo2():
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
print("All the newlines above me should be deleted!")
|
print("All the newlines above me should be kept!")
|
||||||
|
|
||||||
|
|
||||||
def foo3():
|
def foo3():
|
||||||
@ -30,31 +30,31 @@ def foo4():
|
|||||||
class Foo:
|
class Foo:
|
||||||
def bar(self):
|
def bar(self):
|
||||||
|
|
||||||
print("The newline above me should be deleted!")
|
print("The newline above me should be kept!")
|
||||||
|
|
||||||
|
|
||||||
for i in range(5):
|
for i in range(5):
|
||||||
|
|
||||||
print(f"{i}) The line above me should be removed!")
|
print(f"{i}) The line above me should be kept!")
|
||||||
|
|
||||||
|
|
||||||
for i in range(5):
|
for i in range(5):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
print(f"{i}) The lines above me should be removed!")
|
print(f"{i}) The lines above me should be kept!")
|
||||||
|
|
||||||
|
|
||||||
for i in range(5):
|
for i in range(5):
|
||||||
|
|
||||||
for j in range(7):
|
for j in range(7):
|
||||||
|
|
||||||
print(f"{i}) The lines above me should be removed!")
|
print(f"{i}) The lines above me should be kept!")
|
||||||
|
|
||||||
|
|
||||||
if random.randint(0, 3) == 0:
|
if random.randint(0, 3) == 0:
|
||||||
|
|
||||||
print("The new line above me is about to be removed!")
|
print("The new line above me will be kept!")
|
||||||
|
|
||||||
|
|
||||||
if random.randint(0, 3) == 0:
|
if random.randint(0, 3) == 0:
|
||||||
@ -62,43 +62,45 @@ def bar(self):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
print("The new lines above me is about to be removed!")
|
print("The new lines above me will be kept!")
|
||||||
|
|
||||||
|
|
||||||
if random.randint(0, 3) == 0:
|
if random.randint(0, 3) == 0:
|
||||||
|
|
||||||
if random.uniform(0, 1) > 0.5:
|
if random.uniform(0, 1) > 0.5:
|
||||||
print("Two lines above me are about to be removed!")
|
|
||||||
|
print("Two lines above me will be kept!")
|
||||||
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|
||||||
print("The newline above me should be deleted!")
|
print("The newline above me should be kept!")
|
||||||
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
print("The newlines above me should be deleted!")
|
print("The newlines above me should be kept!")
|
||||||
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|
||||||
while False:
|
while False:
|
||||||
|
|
||||||
print("The newlines above me should be deleted!")
|
print("The newlines above me should be kept!")
|
||||||
|
|
||||||
|
|
||||||
with open("/path/to/file.txt", mode="w") as file:
|
with open("/path/to/file.txt", mode="w") as file:
|
||||||
|
|
||||||
file.write("The new line above me is about to be removed!")
|
file.write("The new line above me will be kept!")
|
||||||
|
|
||||||
|
|
||||||
with open("/path/to/file.txt", mode="w") as file:
|
with open("/path/to/file.txt", mode="w") as file:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
file.write("The new lines above me is about to be removed!")
|
file.write("The new lines above me will be kept!")
|
||||||
|
|
||||||
|
|
||||||
with open("/path/to/file.txt", mode="r") as read_file:
|
with open("/path/to/file.txt", mode="r") as read_file:
|
||||||
@ -113,20 +115,24 @@ def bar(self):
|
|||||||
|
|
||||||
|
|
||||||
def foo1():
|
def foo1():
|
||||||
print("The newline above me should be deleted!")
|
|
||||||
|
print("The newline above me should be kept!")
|
||||||
|
|
||||||
|
|
||||||
def foo2():
|
def foo2():
|
||||||
print("All the newlines above me should be deleted!")
|
|
||||||
|
print("All the newlines above me should be kept!")
|
||||||
|
|
||||||
|
|
||||||
def foo3():
|
def foo3():
|
||||||
|
|
||||||
print("No newline above me!")
|
print("No newline above me!")
|
||||||
|
|
||||||
print("There is a newline above me, and that's OK!")
|
print("There is a newline above me, and that's OK!")
|
||||||
|
|
||||||
|
|
||||||
def foo4():
|
def foo4():
|
||||||
|
|
||||||
# There is a comment here
|
# There is a comment here
|
||||||
|
|
||||||
print("The newline above me should not be deleted!")
|
print("The newline above me should not be deleted!")
|
||||||
@ -134,56 +140,73 @@ def foo4():
|
|||||||
|
|
||||||
class Foo:
|
class Foo:
|
||||||
def bar(self):
|
def bar(self):
|
||||||
print("The newline above me should be deleted!")
|
|
||||||
|
print("The newline above me should be kept!")
|
||||||
|
|
||||||
|
|
||||||
for i in range(5):
|
for i in range(5):
|
||||||
print(f"{i}) The line above me should be removed!")
|
|
||||||
|
print(f"{i}) The line above me should be kept!")
|
||||||
|
|
||||||
|
|
||||||
for i in range(5):
|
for i in range(5):
|
||||||
print(f"{i}) The lines above me should be removed!")
|
|
||||||
|
print(f"{i}) The lines above me should be kept!")
|
||||||
|
|
||||||
|
|
||||||
for i in range(5):
|
for i in range(5):
|
||||||
|
|
||||||
for j in range(7):
|
for j in range(7):
|
||||||
print(f"{i}) The lines above me should be removed!")
|
|
||||||
|
print(f"{i}) The lines above me should be kept!")
|
||||||
|
|
||||||
|
|
||||||
if random.randint(0, 3) == 0:
|
if random.randint(0, 3) == 0:
|
||||||
print("The new line above me is about to be removed!")
|
|
||||||
|
print("The new line above me will be kept!")
|
||||||
|
|
||||||
|
|
||||||
if random.randint(0, 3) == 0:
|
if random.randint(0, 3) == 0:
|
||||||
print("The new lines above me is about to be removed!")
|
|
||||||
|
print("The new lines above me will be kept!")
|
||||||
|
|
||||||
|
|
||||||
if random.randint(0, 3) == 0:
|
if random.randint(0, 3) == 0:
|
||||||
|
|
||||||
if random.uniform(0, 1) > 0.5:
|
if random.uniform(0, 1) > 0.5:
|
||||||
print("Two lines above me are about to be removed!")
|
|
||||||
|
print("Two lines above me will be kept!")
|
||||||
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
print("The newline above me should be deleted!")
|
|
||||||
|
print("The newline above me should be kept!")
|
||||||
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
print("The newlines above me should be deleted!")
|
|
||||||
|
print("The newlines above me should be kept!")
|
||||||
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|
||||||
while False:
|
while False:
|
||||||
print("The newlines above me should be deleted!")
|
|
||||||
|
print("The newlines above me should be kept!")
|
||||||
|
|
||||||
|
|
||||||
with open("/path/to/file.txt", mode="w") as file:
|
with open("/path/to/file.txt", mode="w") as file:
|
||||||
file.write("The new line above me is about to be removed!")
|
|
||||||
|
file.write("The new line above me will be kept!")
|
||||||
|
|
||||||
|
|
||||||
with open("/path/to/file.txt", mode="w") as file:
|
with open("/path/to/file.txt", mode="w") as file:
|
||||||
file.write("The new lines above me is about to be removed!")
|
|
||||||
|
file.write("The new lines above me will be kept!")
|
||||||
|
|
||||||
|
|
||||||
with open("/path/to/file.txt", mode="r") as read_file:
|
with open("/path/to/file.txt", mode="r") as read_file:
|
||||||
|
|
||||||
with open("/path/to/output_file.txt", mode="w") as write_file:
|
with open("/path/to/output_file.txt", mode="w") as write_file:
|
||||||
|
|
||||||
write_file.writelines(read_file.readlines())
|
write_file.writelines(read_file.readlines())
|
||||||
|
@ -88,7 +88,6 @@ def foo() -> tuple[int, int, int,]:
|
|||||||
return 2
|
return 2
|
||||||
|
|
||||||
# Magic trailing comma example, with params
|
# Magic trailing comma example, with params
|
||||||
# this is broken - the trailing comma is transferred to the param list. Fixed in preview
|
|
||||||
def foo(a,b) -> tuple[int, int, int,]:
|
def foo(a,b) -> tuple[int, int, int,]:
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
@ -194,30 +193,27 @@ def foo() -> tuple[int, int, int]:
|
|||||||
return 2
|
return 2
|
||||||
|
|
||||||
|
|
||||||
def foo() -> (
|
def foo() -> tuple[
|
||||||
tuple[
|
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
|
||||||
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
|
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
|
||||||
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
|
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
|
||||||
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
|
]:
|
||||||
]
|
|
||||||
):
|
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
|
|
||||||
# Magic trailing comma example
|
# Magic trailing comma example
|
||||||
def foo() -> (
|
def foo() -> tuple[
|
||||||
tuple[
|
int,
|
||||||
int,
|
int,
|
||||||
int,
|
int,
|
||||||
int,
|
]:
|
||||||
]
|
|
||||||
):
|
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
|
|
||||||
# Magic trailing comma example, with params
|
# Magic trailing comma example, with params
|
||||||
# this is broken - the trailing comma is transferred to the param list. Fixed in preview
|
def foo(a, b) -> tuple[
|
||||||
def foo(
|
int,
|
||||||
a, b
|
int,
|
||||||
) -> tuple[int, int, int,]:
|
int,
|
||||||
|
]:
|
||||||
return 2
|
return 2
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# flags: --preview
|
|
||||||
foo = 123 # fmt: skip # noqa: E501 # pylint
|
foo = 123 # fmt: skip # noqa: E501 # pylint
|
||||||
bar = (
|
bar = (
|
||||||
123 ,
|
123 ,
|
@ -1,4 +1,3 @@
|
|||||||
# flags: --preview
|
|
||||||
e = {
|
e = {
|
||||||
"a": fun(msg, "ts"),
|
"a": fun(msg, "ts"),
|
||||||
"longggggggggggggggid": ...,
|
"longggggggggggggggid": ...,
|
@ -1,7 +1,9 @@
|
|||||||
# flags: --preview
|
# flags: --preview
|
||||||
|
# This is testing an issue that is specific to the preview style
|
||||||
{
|
{
|
||||||
"is_update": (up := commit.hash in update_hashes)
|
"is_update": (up := commit.hash in update_hashes)
|
||||||
}
|
}
|
||||||
|
|
||||||
# output
|
# output
|
||||||
|
# This is testing an issue that is specific to the preview style
|
||||||
{"is_update": (up := commit.hash in update_hashes)}
|
{"is_update": (up := commit.hash in update_hashes)}
|
||||||
|
Loading…
Reference in New Issue
Block a user