Closes #2918.
<!-- Changes that affect Black's preview style -->
- Code cell separators `#%%` are now standardised to `# %%` (#2919)
+- Avoid magic-trailing-comma in single-element subscripts (#2942)
### _Blackd_
from black.nodes import WHITESPACE, RARROW, STATEMENT, STANDALONE_COMMENT
from black.nodes import ASSIGNMENTS, OPENING_BRACKETS, CLOSING_BRACKETS
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_walrus_assignment, is_yield, is_vararg, is_multiline_string
from black.nodes import is_stub_suite, is_stub_body, is_atom_with_invisible_parens
prev
and prev.type == token.COMMA
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
)
):
prev
and prev.type == token.COMMA
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.
# We need to explode on those.
from blib2to3.pgen2 import token
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 BRACKETS, OPENING_BRACKETS, CLOSING_BRACKETS
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_one_tuple_between
+from black.nodes import is_one_sequence_between
# types
T = TypeVar("T")
"""Return True if we have a magic trailing comma, that is when:
- there's a trailing comma here
- it's not a one-tuple
+ - it's not a single-element subscript
Additionally, if ensure_removable:
- it's not from square bracket indexing
"""
return True
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:
return True
comma = self.leaves[-1]
if self.is_import:
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
):
return True
"""Individual preview style features."""
string_processing = auto()
+ one_element_subscript = auto()
class Deprecated(UserWarning):
"""
if feature is Preview.string_processing:
return self.preview or self.experimental_string_processing
- # TODO: Remove type ignore comment once preview contains more features
- # than just ESP
- return self.preview # type: ignore
+ return self.preview
def get_cache_key(self) -> str:
if self.target_versions:
List,
Optional,
Set,
+ Tuple,
TypeVar,
Union,
)
)
-def is_one_tuple_between(opening: Leaf, closing: Leaf, leaves: List[Leaf]) -> bool:
- """Return True if content between `opening` and `closing` looks like a one-tuple."""
- if opening.type != token.LPAR and closing.type != token.RPAR:
+def is_one_sequence_between(
+ opening: Leaf,
+ 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
depth = closing.bracket_depth + 1
--- /dev/null
+# 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,],
+]
"long_strings__edge_case",
"long_strings__regression",
"percent_precedence",
+ "one_element_subscript",
]
SOURCES: List[str] = [