cast,
)
-from black.brackets import DOT_PRIORITY, BracketTracker
+from black.brackets import COMMA_PRIORITY, DOT_PRIORITY, BracketTracker
from black.mode import Mode, Preview
from black.nodes import (
BRACKETS,
is_multiline_string,
is_one_sequence_between,
is_type_comment,
+ is_with_or_async_with_stmt,
replace_child,
syms,
whitespace,
"""Is this an import line?"""
return bool(self) and is_import(self.leaves[0])
+ @property
+ def is_with_or_async_with_stmt(self) -> bool:
+ """Is this a with_stmt line?"""
+ return bool(self) and is_with_or_async_with_stmt(self.leaves[0])
+
@property
def is_class(self) -> bool:
"""Is this line a class definition?"""
return False
return self.leaves[-1].type == token.COLON
+ def is_fmt_pass_converted(
+ self, *, first_leaf_matches: Optional[Callable[[Leaf], bool]] = None
+ ) -> bool:
+ """Is this line converted from fmt off/skip code?
+
+ If first_leaf_matches is not None, it only returns True if the first
+ leaf of converted code matches.
+ """
+ if len(self.leaves) != 1:
+ return False
+ leaf = self.leaves[0]
+ if (
+ leaf.type != STANDALONE_COMMENT
+ or leaf.fmt_pass_converted_first_leaf is None
+ ):
+ return False
+ return first_leaf_matches is None or first_leaf_matches(
+ leaf.fmt_pass_converted_first_leaf
+ )
+
def contains_standalone_comments(self, depth_limit: int = sys.maxsize) -> bool:
"""If so, needs to be split before emitting."""
for leaf in self.leaves:
return bool(self.leaves or self.comments)
+@dataclass
+class RHSResult:
+ """Intermediate split result from a right hand split."""
+
+ head: Line
+ body: Line
+ tail: Line
+ opening_bracket: Leaf
+ closing_bracket: Leaf
+
+
@dataclass
class LinesBlock:
"""Class that holds information about a block of formatted lines.
self.previous_line
and self.previous_line.is_import
and not current_line.is_import
+ and not current_line.is_fmt_pass_converted(first_leaf_matches=is_import)
and depth == self.previous_line.depth
):
return (before or 1), 0
def can_omit_invisible_parens(
- line: Line,
+ rhs: RHSResult,
line_length: int,
) -> bool:
- """Does `line` have a shape safe to reformat without optional parens around it?
+ """Does `rhs.body` have a shape safe to reformat without optional parens around it?
Returns True for only a subset of potentially nice looking formattings but
the point is to not return false positives that end up producing lines that
are too long.
"""
+ line = rhs.body
bt = line.bracket_tracker
if not bt.delimiters:
# Without delimiters the optional parentheses are useless.
return True
max_priority = bt.max_delimiter_priority()
- if bt.delimiter_count_with_priority(max_priority) > 1:
+ delimiter_count = bt.delimiter_count_with_priority(max_priority)
+ if delimiter_count > 1:
# With more than one delimiter of a kind the optional parentheses read better.
return False
+ if delimiter_count == 1:
+ if (
+ 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
+ # better. In this case, `rhs.body` is the context managers part of
+ # the with statement. `rhs.head` is the `with (` part on the previous
+ # line.
+ return False
+ # Otherwise it may also read better, but we don't do it today and requires
+ # careful considerations for all possible cases. See
+ # https://github.com/psf/black/issues/2156.
+
if max_priority == DOT_PRIORITY:
# A single stranded method call doesn't require optional parentheses.
return True