Avoid magic-trailing-comma in single-element subscripts (#2942)
Closes #2918.
This commit is contained in:
parent
062b54931d
commit
3800ebd81d
@ -15,6 +15,7 @@
|
|||||||
<!-- Changes that affect Black's preview style -->
|
<!-- Changes that affect Black's preview style -->
|
||||||
|
|
||||||
- Code cell separators `#%%` are now standardised to `# %%` (#2919)
|
- Code cell separators `#%%` are now standardised to `# %%` (#2919)
|
||||||
|
- Avoid magic-trailing-comma in single-element subscripts (#2942)
|
||||||
|
|
||||||
### _Blackd_
|
### _Blackd_
|
||||||
|
|
||||||
|
@ -8,7 +8,12 @@
|
|||||||
from black.nodes import WHITESPACE, RARROW, STATEMENT, STANDALONE_COMMENT
|
from black.nodes import WHITESPACE, RARROW, STATEMENT, STANDALONE_COMMENT
|
||||||
from black.nodes import ASSIGNMENTS, OPENING_BRACKETS, CLOSING_BRACKETS
|
from black.nodes import ASSIGNMENTS, OPENING_BRACKETS, CLOSING_BRACKETS
|
||||||
from black.nodes import Visitor, syms, is_arith_like, ensure_visible
|
from black.nodes import Visitor, syms, is_arith_like, ensure_visible
|
||||||
from black.nodes import is_docstring, is_empty_tuple, is_one_tuple, is_one_tuple_between
|
from black.nodes import (
|
||||||
|
is_docstring,
|
||||||
|
is_empty_tuple,
|
||||||
|
is_one_tuple,
|
||||||
|
is_one_sequence_between,
|
||||||
|
)
|
||||||
from black.nodes import is_name_token, is_lpar_token, is_rpar_token
|
from black.nodes import is_name_token, is_lpar_token, is_rpar_token
|
||||||
from black.nodes import is_walrus_assignment, is_yield, is_vararg, is_multiline_string
|
from black.nodes import is_walrus_assignment, is_yield, is_vararg, is_multiline_string
|
||||||
from black.nodes import is_stub_suite, is_stub_body, is_atom_with_invisible_parens
|
from black.nodes import is_stub_suite, is_stub_body, is_atom_with_invisible_parens
|
||||||
@ -973,7 +978,7 @@ def generate_trailers_to_omit(line: Line, line_length: int) -> Iterator[Set[Leaf
|
|||||||
prev
|
prev
|
||||||
and prev.type == token.COMMA
|
and prev.type == token.COMMA
|
||||||
and leaf.opening_bracket is not None
|
and leaf.opening_bracket is not None
|
||||||
and not is_one_tuple_between(
|
and not is_one_sequence_between(
|
||||||
leaf.opening_bracket, leaf, line.leaves
|
leaf.opening_bracket, leaf, line.leaves
|
||||||
)
|
)
|
||||||
):
|
):
|
||||||
@ -1001,7 +1006,7 @@ def generate_trailers_to_omit(line: Line, line_length: int) -> Iterator[Set[Leaf
|
|||||||
prev
|
prev
|
||||||
and prev.type == token.COMMA
|
and prev.type == token.COMMA
|
||||||
and leaf.opening_bracket is not None
|
and leaf.opening_bracket is not None
|
||||||
and not is_one_tuple_between(leaf.opening_bracket, leaf, line.leaves)
|
and not is_one_sequence_between(leaf.opening_bracket, leaf, line.leaves)
|
||||||
):
|
):
|
||||||
# Never omit bracket pairs with trailing commas.
|
# Never omit bracket pairs with trailing commas.
|
||||||
# We need to explode on those.
|
# We need to explode on those.
|
||||||
|
@ -17,12 +17,12 @@
|
|||||||
from blib2to3.pgen2 import token
|
from blib2to3.pgen2 import token
|
||||||
|
|
||||||
from black.brackets import BracketTracker, DOT_PRIORITY
|
from black.brackets import BracketTracker, DOT_PRIORITY
|
||||||
from black.mode import Mode
|
from black.mode import Mode, Preview
|
||||||
from black.nodes import STANDALONE_COMMENT, TEST_DESCENDANTS
|
from black.nodes import STANDALONE_COMMENT, TEST_DESCENDANTS
|
||||||
from black.nodes import BRACKETS, OPENING_BRACKETS, CLOSING_BRACKETS
|
from black.nodes import BRACKETS, OPENING_BRACKETS, CLOSING_BRACKETS
|
||||||
from black.nodes import syms, whitespace, replace_child, child_towards
|
from black.nodes import syms, whitespace, replace_child, child_towards
|
||||||
from black.nodes import is_multiline_string, is_import, is_type_comment
|
from black.nodes import is_multiline_string, is_import, is_type_comment
|
||||||
from black.nodes import is_one_tuple_between
|
from black.nodes import is_one_sequence_between
|
||||||
|
|
||||||
# types
|
# types
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
@ -254,6 +254,7 @@ def has_magic_trailing_comma(
|
|||||||
"""Return True if we have a magic trailing comma, that is when:
|
"""Return True if we have a magic trailing comma, that is when:
|
||||||
- there's a trailing comma here
|
- there's a trailing comma here
|
||||||
- it's not a one-tuple
|
- it's not a one-tuple
|
||||||
|
- it's not a single-element subscript
|
||||||
Additionally, if ensure_removable:
|
Additionally, if ensure_removable:
|
||||||
- it's not from square bracket indexing
|
- it's not from square bracket indexing
|
||||||
"""
|
"""
|
||||||
@ -268,6 +269,20 @@ def has_magic_trailing_comma(
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
if closing.type == token.RSQB:
|
if closing.type == token.RSQB:
|
||||||
|
if (
|
||||||
|
Preview.one_element_subscript in self.mode
|
||||||
|
and closing.parent
|
||||||
|
and closing.parent.type == syms.trailer
|
||||||
|
and closing.opening_bracket
|
||||||
|
and is_one_sequence_between(
|
||||||
|
closing.opening_bracket,
|
||||||
|
closing,
|
||||||
|
self.leaves,
|
||||||
|
brackets=(token.LSQB, token.RSQB),
|
||||||
|
)
|
||||||
|
):
|
||||||
|
return False
|
||||||
|
|
||||||
if not ensure_removable:
|
if not ensure_removable:
|
||||||
return True
|
return True
|
||||||
comma = self.leaves[-1]
|
comma = self.leaves[-1]
|
||||||
@ -276,7 +291,7 @@ def has_magic_trailing_comma(
|
|||||||
if self.is_import:
|
if self.is_import:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if closing.opening_bracket is not None and not is_one_tuple_between(
|
if closing.opening_bracket is not None and not is_one_sequence_between(
|
||||||
closing.opening_bracket, closing, self.leaves
|
closing.opening_bracket, closing, self.leaves
|
||||||
):
|
):
|
||||||
return True
|
return True
|
||||||
|
@ -127,6 +127,7 @@ class Preview(Enum):
|
|||||||
"""Individual preview style features."""
|
"""Individual preview style features."""
|
||||||
|
|
||||||
string_processing = auto()
|
string_processing = auto()
|
||||||
|
one_element_subscript = auto()
|
||||||
|
|
||||||
|
|
||||||
class Deprecated(UserWarning):
|
class Deprecated(UserWarning):
|
||||||
@ -162,9 +163,7 @@ def __contains__(self, feature: Preview) -> bool:
|
|||||||
"""
|
"""
|
||||||
if feature is Preview.string_processing:
|
if feature is Preview.string_processing:
|
||||||
return self.preview or self.experimental_string_processing
|
return self.preview or self.experimental_string_processing
|
||||||
# TODO: Remove type ignore comment once preview contains more features
|
return self.preview
|
||||||
# than just ESP
|
|
||||||
return self.preview # type: ignore
|
|
||||||
|
|
||||||
def get_cache_key(self) -> str:
|
def get_cache_key(self) -> str:
|
||||||
if self.target_versions:
|
if self.target_versions:
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
List,
|
List,
|
||||||
Optional,
|
Optional,
|
||||||
Set,
|
Set,
|
||||||
|
Tuple,
|
||||||
TypeVar,
|
TypeVar,
|
||||||
Union,
|
Union,
|
||||||
)
|
)
|
||||||
@ -559,9 +560,14 @@ def is_one_tuple(node: LN) -> bool:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def is_one_tuple_between(opening: Leaf, closing: Leaf, leaves: List[Leaf]) -> bool:
|
def is_one_sequence_between(
|
||||||
"""Return True if content between `opening` and `closing` looks like a one-tuple."""
|
opening: Leaf,
|
||||||
if opening.type != token.LPAR and closing.type != token.RPAR:
|
closing: Leaf,
|
||||||
|
leaves: List[Leaf],
|
||||||
|
brackets: Tuple[int, int] = (token.LPAR, token.RPAR),
|
||||||
|
) -> bool:
|
||||||
|
"""Return True if content between `opening` and `closing` is a one-sequence."""
|
||||||
|
if (opening.type, closing.type) != brackets:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
depth = closing.bracket_depth + 1
|
depth = closing.bracket_depth + 1
|
||||||
|
36
tests/data/one_element_subscript.py
Normal file
36
tests/data/one_element_subscript.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# We should not treat the trailing comma
|
||||||
|
# in a single-element subscript.
|
||||||
|
a: tuple[int,]
|
||||||
|
b = tuple[int,]
|
||||||
|
|
||||||
|
# The magic comma still applies to multi-element subscripts.
|
||||||
|
c: tuple[int, int,]
|
||||||
|
d = tuple[int, int,]
|
||||||
|
|
||||||
|
# Magic commas still work as expected for non-subscripts.
|
||||||
|
small_list = [1,]
|
||||||
|
list_of_types = [tuple[int,],]
|
||||||
|
|
||||||
|
# output
|
||||||
|
# We should not treat the trailing comma
|
||||||
|
# in a single-element subscript.
|
||||||
|
a: tuple[int,]
|
||||||
|
b = tuple[int,]
|
||||||
|
|
||||||
|
# The magic comma still applies to multi-element subscripts.
|
||||||
|
c: tuple[
|
||||||
|
int,
|
||||||
|
int,
|
||||||
|
]
|
||||||
|
d = tuple[
|
||||||
|
int,
|
||||||
|
int,
|
||||||
|
]
|
||||||
|
|
||||||
|
# Magic commas still work as expected for non-subscripts.
|
||||||
|
small_list = [
|
||||||
|
1,
|
||||||
|
]
|
||||||
|
list_of_types = [
|
||||||
|
tuple[int,],
|
||||||
|
]
|
@ -80,6 +80,7 @@
|
|||||||
"long_strings__edge_case",
|
"long_strings__edge_case",
|
||||||
"long_strings__regression",
|
"long_strings__regression",
|
||||||
"percent_precedence",
|
"percent_precedence",
|
||||||
|
"one_element_subscript",
|
||||||
]
|
]
|
||||||
|
|
||||||
SOURCES: List[str] = [
|
SOURCES: List[str] = [
|
||||||
|
Loading…
Reference in New Issue
Block a user