def standalone_comment_split( line: Line, features: Collection[Feature] = () ) -> Iterator[Line]: """Split standalone comments from the rest of the line.""" if not line.contains_standalone_comments(0): raise CannotSplit("Line does not have any standalone comments") current_line = Line( mode=line.mode, depth=line.depth, inside_brackets=line.inside_brackets ) def append_to_line(leaf: Leaf) -> Iterator[Line]: """Append `leaf` to current line or to new line if appending impossible.""" nonlocal current_line try: current_line.append_safe(leaf, preformatted=True) except ValueError: yield current_line current_line = Line( line.mode, depth=line.depth, inside_brackets=line.inside_brackets ) current_line.append(leaf) for leaf in line.leaves: yield from append_to_line(leaf) for comment_after in line.comments_after(leaf): yield from append_to_line(comment_after) if current_line: yield current_line
def bracket_split_build_line( leaves: List[Leaf], original: Line, opening_bracket: Leaf, *, is_body: bool = False ) -> Line: """Return a new line with given `leaves` and respective comments from `original`. If `is_body` is True, the result line is one-indented inside brackets and as such has its first leaf's prefix normalized and a trailing comma added when expected. """ result = Line(mode=original.mode, depth=original.depth) if is_body: result.inside_brackets = True result.depth += 1 if leaves: # Since body is a new indent level, remove spurious leading whitespace. normalize_prefix(leaves[0], inside_brackets=True) # Ensure a trailing comma for imports and standalone function arguments, but # be careful not to add one after any comments or within type annotations. no_commas = ( original.is_def and opening_bracket.value == "(" and not any(leaf.type == token.COMMA for leaf in leaves) # In particular, don't add one within a parenthesized return annotation. # Unfortunately the indicator we're in a return annotation (RARROW) may # be defined directly in the parent node, the parent of the parent ... # and so on depending on how complex the return annotation is. # This isn't perfect and there's some false negatives but they are in # contexts were a comma is actually fine. and not any( node.prev_sibling.type == RARROW for node in ( leaves[0].parent, getattr(leaves[0].parent, "parent", None), ) if isinstance(node, Node) and isinstance(node.prev_sibling, Leaf) ) ) if original.is_import or no_commas: for i in range(len(leaves) - 1, -1, -1): if leaves[i].type == STANDALONE_COMMENT: continue if leaves[i].type != token.COMMA: new_comma = Leaf(token.COMMA, ",") leaves.insert(i + 1, new_comma) break # Populate the line for leaf in leaves: result.append(leaf, preformatted=True) for comment_after in original.comments_after(leaf): result.append(comment_after, preformatted=True) if is_body and should_split_line(result, opening_bracket): result.should_split_rhs = True return result
def bracket_split_build_line(leaves: List[Leaf], original: Line, opening_bracket: Leaf, *, is_body: bool = False) -> Line: """Return a new line with given `leaves` and respective comments from `original`. If `is_body` is True, the result line is one-indented inside brackets and as such has its first leaf's prefix normalized and a trailing comma added when expected. """ result = Line(mode=original.mode, depth=original.depth) if is_body: result.inside_brackets = True result.depth += 1 if leaves: # Since body is a new indent level, remove spurious leading whitespace. normalize_prefix(leaves[0], inside_brackets=True) # Ensure a trailing comma for imports and standalone function arguments, but # be careful not to add one after any comments or within type annotations. no_commas = (original.is_def and opening_bracket.value == "(" and not any(leaf.type == token.COMMA for leaf in leaves)) if original.is_import or no_commas: for i in range(len(leaves) - 1, -1, -1): if leaves[i].type == STANDALONE_COMMENT: continue if leaves[i].type != token.COMMA and not original.is_import: new_comma = Leaf(token.COMMA, ",") leaves.insert(i + 1, new_comma) break # Populate the line for leaf in leaves: result.append(leaf, preformatted=True) for comment_after in original.comments_after(leaf): result.append(comment_after, preformatted=True) if is_body and should_split_line(result, opening_bracket): result.should_split_rhs = True return result
def delimiter_split(line: Line, features: Collection[Feature] = ()) -> Iterator[Line]: """Split according to delimiters of the highest priority. If the appropriate Features are given, the split will add trailing commas also in function signatures and calls that contain `*` and `**`. """ try: last_leaf = line.leaves[-1] except IndexError: raise CannotSplit("Line empty") from None bt = line.bracket_tracker try: delimiter_priority = bt.max_delimiter_priority(exclude={id(last_leaf)}) except ValueError: raise CannotSplit("No delimiters found") from None if delimiter_priority == DOT_PRIORITY: if bt.delimiter_count_with_priority(delimiter_priority) == 1: raise CannotSplit("Splitting a single attribute from its owner looks wrong") current_line = Line( mode=line.mode, depth=line.depth, inside_brackets=line.inside_brackets ) lowest_depth = sys.maxsize trailing_comma_safe = True def append_to_line(leaf: Leaf) -> Iterator[Line]: """Append `leaf` to current line or to new line if appending impossible.""" nonlocal current_line try: current_line.append_safe(leaf, preformatted=True) except ValueError: yield current_line current_line = Line( mode=line.mode, depth=line.depth, inside_brackets=line.inside_brackets ) current_line.append(leaf) for leaf in line.leaves: yield from append_to_line(leaf) for comment_after in line.comments_after(leaf): yield from append_to_line(comment_after) lowest_depth = min(lowest_depth, leaf.bracket_depth) if leaf.bracket_depth == lowest_depth: if is_vararg(leaf, within={syms.typedargslist}): trailing_comma_safe = ( trailing_comma_safe and Feature.TRAILING_COMMA_IN_DEF in features ) elif is_vararg(leaf, within={syms.arglist, syms.argument}): trailing_comma_safe = ( trailing_comma_safe and Feature.TRAILING_COMMA_IN_CALL in features ) leaf_priority = bt.delimiters.get(id(leaf)) if leaf_priority == delimiter_priority: yield current_line current_line = Line( mode=line.mode, depth=line.depth, inside_brackets=line.inside_brackets ) if current_line: if ( trailing_comma_safe and delimiter_priority == COMMA_PRIORITY and current_line.leaves[-1].type != token.COMMA and current_line.leaves[-1].type != STANDALONE_COMMENT ): new_comma = Leaf(token.COMMA, ",") current_line.append(new_comma) yield current_line