Ejemplo n.º 1
0
def _InsertPseudoParentheses(node):
    """Insert pseudo parentheses so that dicts can be formatted correctly."""
    comment_node = None
    if isinstance(node, pytree.Node):
        if node.children[-1].type == grammar_token.COMMENT:
            comment_node = node.children[-1].clone()
            node.children[-1].remove()

    first = pytree_utils.FirstLeafNode(node)
    last = pytree_utils.LastLeafNode(node)

    if first == last and first.type == grammar_token.COMMENT:
        # A comment was inserted before the value, which is a pytree.Leaf.
        # Encompass the dictionary's value into an ATOM node.
        last = first.next_sibling
        last_clone = last.clone()
        new_node = pytree.Node(syms.atom, [first.clone(), last_clone])
        for orig_leaf, clone_leaf in zip(last.leaves(), last_clone.leaves()):
            pytree_utils.CopyYapfAnnotations(orig_leaf, clone_leaf)
            if hasattr(orig_leaf, 'is_pseudo'):
                clone_leaf.is_pseudo = orig_leaf.is_pseudo

        node.replace(new_node)
        node = new_node
        last.remove()

        first = pytree_utils.FirstLeafNode(node)
        last = pytree_utils.LastLeafNode(node)

    lparen = pytree.Leaf(grammar_token.LPAR,
                         u'(',
                         context=('', (first.get_lineno(), first.column - 1)))
    last_lineno = last.get_lineno()
    if last.type == grammar_token.STRING and '\n' in last.value:
        last_lineno += last.value.count('\n')

    if last.type == grammar_token.STRING and '\n' in last.value:
        last_column = len(last.value.split('\n')[-1]) + 1
    else:
        last_column = last.column + len(last.value) + 1
    rparen = pytree.Leaf(grammar_token.RPAR,
                         u')',
                         context=('', (last_lineno, last_column)))

    lparen.is_pseudo = True
    rparen.is_pseudo = True

    if isinstance(node, pytree.Node):
        node.insert_child(0, lparen)
        node.append_child(rparen)
        if comment_node:
            node.append_child(comment_node)
        _AppendFirstLeafTokenSubtype(node, subtypes.DICTIONARY_VALUE)
    else:
        clone = node.clone()
        for orig_leaf, clone_leaf in zip(node.leaves(), clone.leaves()):
            pytree_utils.CopyYapfAnnotations(orig_leaf, clone_leaf)
        new_node = pytree.Node(syms.atom, [lparen, clone, rparen])
        node.replace(new_node)
        _AppendFirstLeafTokenSubtype(clone, subtypes.DICTIONARY_VALUE)
Ejemplo n.º 2
0
 def Visit_subscriptlist(self, node):  # pylint: disable=invalid-name
     # subscriptlist ::= subscript (',' subscript)* [',']
     self.DefaultNodeVisit(node)
     _SetSplitPenalty(pytree_utils.FirstLeafNode(node), 0)
     prev_child = None
     for child in node.children:
         if prev_child and prev_child.type == grammar_token.COMMA:
             _SetSplitPenalty(pytree_utils.FirstLeafNode(child), 0)
         prev_child = child
Ejemplo n.º 3
0
def _StronglyConnectedCompOp(op):
    if (len(op.children[1].children) == 2
            and pytree_utils.NodeName(op.children[1]) == 'comp_op'):
        if (pytree_utils.FirstLeafNode(op.children[1]).value == 'not'
                and pytree_utils.LastLeafNode(op.children[1]).value == 'in'):
            return True
        if (pytree_utils.FirstLeafNode(op.children[1]).value == 'is'
                and pytree_utils.LastLeafNode(op.children[1]).value == 'not'):
            return True
    if (isinstance(op.children[1], pytree.Leaf)
            and op.children[1].value in _COMP_OPS):
        return True
    return False
Ejemplo n.º 4
0
    def Visit_tname(self, node):  # pylint: disable=invalid-name
        # tname ::= NAME [':' test]
        self.DefaultNodeVisit(node)

        for index in py3compat.range(1, len(node.children) - 1):
            child = node.children[index]
            if isinstance(child, pytree.Leaf) and child.value == ':':
                _SetSplitPenalty(
                    pytree_utils.FirstLeafNode(node.children[index]),
                    NAMED_ASSIGN)
                _SetSplitPenalty(
                    pytree_utils.FirstLeafNode(node.children[index + 1]),
                    NAMED_ASSIGN)
Ejemplo n.º 5
0
    def Visit_argument(self, node):  # pylint: disable=invalid-name
        # argument ::= test [comp_for] | test '=' test  # Really [keyword '='] test
        self.DefaultNodeVisit(node)

        for index in py3compat.range(1, len(node.children) - 1):
            child = node.children[index]
            if isinstance(child, pytree.Leaf) and child.value == '=':
                _SetSplitPenalty(
                    pytree_utils.FirstLeafNode(node.children[index]),
                    NAMED_ASSIGN)
                _SetSplitPenalty(
                    pytree_utils.FirstLeafNode(node.children[index + 1]),
                    NAMED_ASSIGN)
Ejemplo n.º 6
0
 def Visit_and_test(self, node):  # pylint: disable=invalid-name
     # and_test ::= not_test ('and' not_test)*
     self.DefaultNodeVisit(node)
     _IncreasePenalty(node, AND_TEST)
     index = 1
     while index + 1 < len(node.children):
         if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'):
             _DecrementSplitPenalty(
                 pytree_utils.FirstLeafNode(node.children[index]), AND_TEST)
         else:
             _DecrementSplitPenalty(
                 pytree_utils.FirstLeafNode(node.children[index + 1]),
                 AND_TEST)
         index += 2
Ejemplo n.º 7
0
 def Visit_comparison(self, node):  # pylint: disable=invalid-name
     # comparison ::= expr (comp_op expr)*
     self.DefaultNodeVisit(node)
     if len(node.children) == 3 and _StronglyConnectedCompOp(node):
         _IncreasePenalty(node.children[1], VERY_STRONGLY_CONNECTED)
         _SetSplitPenalty(pytree_utils.FirstLeafNode(node.children[2]),
                          STRONGLY_CONNECTED)
     else:
         _IncreasePenalty(node, COMPARISON)
Ejemplo n.º 8
0
def _SetExpressionOperandPenalty(node, ops):
    for index in py3compat.range(1, len(node.children) - 1):
        child = node.children[index]
        if pytree_utils.NodeName(child) in ops:
            if style.Get('SPLIT_BEFORE_ARITHMETIC_OPERATOR'):
                _SetSplitPenalty(
                    child, style.Get('SPLIT_PENALTY_ARITHMETIC_OPERATOR'))
            else:
                _SetSplitPenalty(
                    pytree_utils.FirstLeafNode(node.children[index + 1]),
                    style.Get('SPLIT_PENALTY_ARITHMETIC_OPERATOR'))
Ejemplo n.º 9
0
def _SetBitwiseOperandPenalty(node, op):
    for index in py3compat.range(1, len(node.children) - 1):
        child = node.children[index]
        if isinstance(child, pytree.Leaf) and child.value == op:
            if style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'):
                _SetSplitPenalty(child,
                                 style.Get('SPLIT_PENALTY_BITWISE_OPERATOR'))
            else:
                _SetSplitPenalty(
                    pytree_utils.FirstLeafNode(node.children[index + 1]),
                    style.Get('SPLIT_PENALTY_BITWISE_OPERATOR'))
Ejemplo n.º 10
0
 def Visit_testlist_gexp(self, node):  # pylint: disable=invalid-name
     self.DefaultNodeVisit(node)
     prev_was_comma = False
     for child in node.children:
         if isinstance(child, pytree.Leaf) and child.value == ',':
             _SetUnbreakable(child)
             prev_was_comma = True
         else:
             if prev_was_comma:
                 _SetSplitPenalty(pytree_utils.FirstLeafNode(child),
                                  TOGETHER)
             prev_was_comma = False
Ejemplo n.º 11
0
    def DefaultNodeVisit(self, node):
        """Override the default visitor for Node.

    This will set the blank lines required if the last entity was a class or
    function.

    Arguments:
      node: (pytree.Node) The node to visit.
    """
        if self.last_was_class_or_function:
            if pytree_utils.NodeName(node) in _PYTHON_STATEMENTS:
                leaf = pytree_utils.FirstLeafNode(node)
                _SetNumNewlines(leaf, self._GetNumNewlines(leaf))
        self.last_was_class_or_function = False
        super(_BlankLineCalculator, self).DefaultNodeVisit(node)
Ejemplo n.º 12
0
    def Visit_dictsetmaker(self, node):  # pylint: disable=invalid-name
        # dictsetmaker ::= (test ':' test (comp_for |
        #                                   (',' test ':' test)* [','])) |
        #                  (test (comp_for | (',' test)* [',']))
        for child in node.children:
            self.Visit(child)

        comp_for = False
        dict_maker = False

        for child in node.children:
            if pytree_utils.NodeName(child) == 'comp_for':
                comp_for = True
                _AppendFirstLeafTokenSubtype(child,
                                             subtypes.DICT_SET_GENERATOR)
            elif child.type in (grammar_token.COLON, grammar_token.DOUBLESTAR):
                dict_maker = True

        if not comp_for and dict_maker:
            last_was_colon = False
            unpacking = False
            for child in node.children:
                if child.type == grammar_token.DOUBLESTAR:
                    _AppendFirstLeafTokenSubtype(child,
                                                 subtypes.KWARGS_STAR_STAR)
                if last_was_colon:
                    if style.Get('INDENT_DICTIONARY_VALUE'):
                        _InsertPseudoParentheses(child)
                    else:
                        _AppendFirstLeafTokenSubtype(child,
                                                     subtypes.DICTIONARY_VALUE)
                elif (isinstance(child, pytree.Node)
                      or (not child.value.startswith('#')
                          and child.value not in '{:,')):
                    # Mark the first leaf of a key entry as a DICTIONARY_KEY. We
                    # normally want to split before them if the dictionary cannot exist
                    # on a single line.
                    if not unpacking or pytree_utils.FirstLeafNode(
                            child).value == '**':
                        _AppendFirstLeafTokenSubtype(child,
                                                     subtypes.DICTIONARY_KEY)
                    _AppendSubtypeRec(child, subtypes.DICTIONARY_KEY_PART)
                last_was_colon = child.type == grammar_token.COLON
                if child.type == grammar_token.DOUBLESTAR:
                    unpacking = True
                elif last_was_colon:
                    unpacking = False
Ejemplo n.º 13
0
def _IncreasePenalty(node, amt):
    """Increase a penalty annotation on children nodes."""
    def RecExpression(node, first_child_leaf):
        if node is first_child_leaf:
            return

        if isinstance(node, pytree.Leaf):
            if node.value in {'(', 'for'}:
                return
            penalty = pytree_utils.GetNodeAnnotation(
                node, pytree_utils.Annotation.SPLIT_PENALTY, default=0)
            _SetSplitPenalty(node, penalty + amt)
        else:
            for child in node.children:
                RecExpression(child, first_child_leaf)

    RecExpression(node, pytree_utils.FirstLeafNode(node))
Ejemplo n.º 14
0
def _SetExpressionPenalty(node, penalty):
    """Set a penalty annotation on children nodes."""
    def RecExpression(node, first_child_leaf):
        if node is first_child_leaf:
            return

        if isinstance(node, pytree.Leaf):
            if node.value in {'(', 'for', 'if'}:
                return
            penalty_annotation = pytree_utils.GetNodeAnnotation(
                node, pytree_utils.Annotation.SPLIT_PENALTY, default=0)
            if penalty_annotation < penalty:
                _SetSplitPenalty(node, penalty)
        else:
            for child in node.children:
                RecExpression(child, first_child_leaf)

    RecExpression(node, pytree_utils.FirstLeafNode(node))
Ejemplo n.º 15
0
 def Visit_atom(self, node):  # pylint: disable=invalid-name
     # atom ::= ('(' [yield_expr|testlist_gexp] ')'
     #           '[' [listmaker] ']' |
     #           '{' [dictsetmaker] '}')
     self.DefaultNodeVisit(node)
     if (node.children[0].value == '('
             and not hasattr(node.children[0], 'is_pseudo')):
         if node.children[-1].value == ')':
             if pytree_utils.NodeName(node.parent) == 'if_stmt':
                 _SetSplitPenalty(node.children[-1], STRONGLY_CONNECTED)
             else:
                 if len(node.children) > 2:
                     _SetSplitPenalty(
                         pytree_utils.FirstLeafNode(node.children[1]), EXPR)
                 _SetSplitPenalty(node.children[-1], ATOM)
     elif node.children[0].value in '[{' and len(node.children) == 2:
         # Keep empty containers together if we can.
         _SetUnbreakable(node.children[-1])
Ejemplo n.º 16
0
    def Visit_power(self, node):  # pylint: disable=invalid-name,missing-docstring
        # power ::= atom trailer* ['**' factor]
        self.DefaultNodeVisit(node)

        # When atom is followed by a trailer, we can not break between them.
        # E.g. arr[idx] - no break allowed between 'arr' and '['.
        if (len(node.children) > 1
                and pytree_utils.NodeName(node.children[1]) == 'trailer'):
            # children[1] itself is a whole trailer: we don't want to
            # mark all of it as unbreakable, only its first token: (, [ or .
            first = pytree_utils.FirstLeafNode(node.children[1])
            if first.value != '.':
                _SetUnbreakable(node.children[1].children[0])

            # A special case when there are more trailers in the sequence. Given:
            #   atom tr1 tr2
            # The last token of tr1 and the first token of tr2 comprise an unbreakable
            # region. For example: foo.bar.baz(1)
            # We can't put breaks between either of the '.', '(', or '[' and the names
            # *preceding* them.
            prev_trailer_idx = 1
            while prev_trailer_idx < len(node.children) - 1:
                cur_trailer_idx = prev_trailer_idx + 1
                cur_trailer = node.children[cur_trailer_idx]
                if pytree_utils.NodeName(cur_trailer) != 'trailer':
                    break

                # Now we know we have two trailers one after the other
                prev_trailer = node.children[prev_trailer_idx]
                if prev_trailer.children[-1].value != ')':
                    # Set the previous node unbreakable if it's not a function call:
                    #   atom tr1() tr2
                    # It may be necessary (though undesirable) to split up a previous
                    # function call's parentheses to the next line.
                    _SetStronglyConnected(prev_trailer.children[-1])
                _SetStronglyConnected(cur_trailer.children[0])
                prev_trailer_idx = cur_trailer_idx

        # We don't want to split before the last ')' of a function call. This also
        # takes care of the special case of:
        #   atom tr1 tr2 ... trn
        # where the 'tr#' are trailers that may end in a ')'.
        for trailer in node.children[1:]:
            if pytree_utils.NodeName(trailer) != 'trailer':
                break
            if trailer.children[0].value in '([':
                if len(trailer.children) > 2:
                    stypes = pytree_utils.GetNodeAnnotation(
                        trailer.children[0], pytree_utils.Annotation.SUBTYPE)
                    if stypes and subtypes.SUBSCRIPT_BRACKET in stypes:
                        _SetStronglyConnected(
                            pytree_utils.FirstLeafNode(trailer.children[1]))

                    last_child_node = pytree_utils.LastLeafNode(trailer)
                    if last_child_node.value.strip().startswith('#'):
                        last_child_node = last_child_node.prev_sibling
                    if not (style.Get('INDENT_CLOSING_BRACKETS')
                            or style.Get('DEDENT_CLOSING_BRACKETS')):
                        last = pytree_utils.LastLeafNode(
                            last_child_node.prev_sibling)
                        if last.value != ',':
                            if last_child_node.value == ']':
                                _SetUnbreakable(last_child_node)
                            else:
                                _SetSplitPenalty(last_child_node,
                                                 VERY_STRONGLY_CONNECTED)
                else:
                    # If the trailer's children are '()', then make it a strongly
                    # connected region.  It's sometimes necessary, though undesirable, to
                    # split the two.
                    _SetStronglyConnected(trailer.children[-1])
Ejemplo n.º 17
0
    def Visit_trailer(self, node):  # pylint: disable=invalid-name
        # trailer ::= '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
        if node.children[0].value == '.':
            before = style.Get('SPLIT_BEFORE_DOT')
            _SetSplitPenalty(
                node.children[0],
                VERY_STRONGLY_CONNECTED if before else DOTTED_NAME)
            _SetSplitPenalty(
                node.children[1],
                DOTTED_NAME if before else VERY_STRONGLY_CONNECTED)
        elif len(node.children) == 2:
            # Don't split an empty argument list if at all possible.
            _SetSplitPenalty(node.children[1], VERY_STRONGLY_CONNECTED)
        elif len(node.children) == 3:
            name = pytree_utils.NodeName(node.children[1])
            if name in {'argument', 'comparison'}:
                # Don't split an argument list with one element if at all possible.
                _SetStronglyConnected(node.children[1])
                if (len(node.children[1].children) > 1
                        and pytree_utils.NodeName(
                            node.children[1].children[1]) == 'comp_for'):
                    # Don't penalize splitting before a comp_for expression.
                    _SetSplitPenalty(
                        pytree_utils.FirstLeafNode(node.children[1]), 0)
                else:
                    _SetSplitPenalty(
                        pytree_utils.FirstLeafNode(node.children[1]),
                        ONE_ELEMENT_ARGUMENT)
            elif (node.children[0].type == grammar_token.LSQB
                  and len(node.children[1].children) > 2
                  and (name.endswith('_test') or name.endswith('_expr'))):
                _SetStronglyConnected(node.children[1].children[0])
                _SetStronglyConnected(node.children[1].children[2])

                # Still allow splitting around the operator.
                split_before = (
                    (name.endswith('_test')
                     and style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'))
                    or (name.endswith('_expr')
                        and style.Get('SPLIT_BEFORE_BITWISE_OPERATOR')))
                if split_before:
                    _SetSplitPenalty(
                        pytree_utils.LastLeafNode(
                            node.children[1].children[1]), 0)
                else:
                    _SetSplitPenalty(
                        pytree_utils.FirstLeafNode(
                            node.children[1].children[2]), 0)

                # Don't split the ending bracket of a subscript list.
                _RecAnnotate(node.children[-1],
                             pytree_utils.Annotation.SPLIT_PENALTY,
                             VERY_STRONGLY_CONNECTED)
            elif name not in {
                    'arglist', 'argument', 'term', 'or_test', 'and_test',
                    'comparison', 'atom', 'power'
            }:
                # Don't split an argument list with one element if at all possible.
                stypes = pytree_utils.GetNodeAnnotation(
                    pytree_utils.FirstLeafNode(node),
                    pytree_utils.Annotation.SUBTYPE)
                if stypes and subtypes.SUBSCRIPT_BRACKET in stypes:
                    _IncreasePenalty(node, SUBSCRIPT)

                    # Bump up the split penalty for the first part of a subscript. We
                    # would rather not split there.
                    _IncreasePenalty(node.children[1], CONNECTED)
                else:
                    _SetStronglyConnected(node.children[1], node.children[2])

            if name == 'arglist':
                _SetStronglyConnected(node.children[-1])

        self.DefaultNodeVisit(node)
Ejemplo n.º 18
0
def _StartsInZerothColumn(node):
    return (pytree_utils.FirstLeafNode(node).column == 0
            or (_AsyncFunction(node) and node.prev_sibling.column == 0))
Ejemplo n.º 19
0
 def Visit_comp_for(self, node):  # pylint: disable=invalid-name
     # comp_for ::= 'for' exprlist 'in' testlist_safe [comp_iter]
     _SetSplitPenalty(pytree_utils.FirstLeafNode(node), 0)
     _SetStronglyConnected(*node.children[1:])
     self.DefaultNodeVisit(node)
Ejemplo n.º 20
0
def _SetMustSplitOnFirstLeaf(node):
    """Set the "must split" annotation on the first leaf node."""
    pytree_utils.SetNodeAnnotation(pytree_utils.FirstLeafNode(node),
                                   pytree_utils.Annotation.MUST_SPLIT, True)