Example #1
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],
                       STRONGLY_CONNECTED if before else DOTTED_NAME)
      _SetSplitPenalty(node.children[1],
                       DOTTED_NAME if before else 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 (pytree_utils.NodeName(node.children[0]) == '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.
        _SetVeryStronglyConnected(node.children[-1])
      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.
        subtypes = pytree_utils.GetNodeAnnotation(
            pytree_utils.FirstLeafNode(node), pytree_utils.Annotation.SUBTYPE)
        if subtypes and format_token.Subtype.SUBSCRIPT_BRACKET in subtypes:
          _IncreasePenalty(node, SUBSCRIPT)
        else:
          _SetStronglyConnected(node.children[1], node.children[2])

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

    self.DefaultNodeVisit(node)
Example #2
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)
Example #3
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 pytree_utils.NodeName(prev_child) == 'COMMA':
       _SetSplitPenalty(pytree_utils.FirstLeafNode(child), 0)
     prev_child = child
Example #4
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):
     _SetSplitPenalty(
         pytree_utils.FirstLeafNode(node.children[1]), STRONGLY_CONNECTED)
     _SetSplitPenalty(
         pytree_utils.FirstLeafNode(node.children[2]), STRONGLY_CONNECTED)
   else:
     _IncreasePenalty(node, COMPARISON)
Example #5
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)
Example #6
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)
Example #7
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
Example #8
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 {'==', 'in'}):
        return True
    return False
Example #9
0
    def Visit_trailer(self, node):  # pylint: disable=invalid-name
        for child in node.children:
            self.Visit(child)

        if len(node.children) != 3:
            return
        if pytree_utils.NodeName(node.children[0]) != 'LPAR':
            return

        if pytree_utils.NodeName(node.children[1]) == 'arglist':
            for child in node.children[1].children:
                pytree_utils.SetOpeningBracket(
                    pytree_utils.FirstLeafNode(child), node.children[0])
        else:
            pytree_utils.SetOpeningBracket(
                pytree_utils.FirstLeafNode(node.children[1]), node.children[0])
Example #10
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'))
Example #11
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'))
Example #12
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
    def Visit_atom(self, node):  # pylint: disable=invalid-name
        for child in node.children:
            self.Visit(child)

        if len(node.children) != 3:
            return
        if node.children[0].type != grammar_token.LPAR:
            return

        for child in node.children[1].children:
            pytree_utils.SetOpeningBracket(pytree_utils.FirstLeafNode(child),
                                           node.children[0])
Example #14
0
  def Visit_term(self, node):  # pylint: disable=invalid-name
    # term ::= factor (('*'|'@'|'/'|'%'|'//') factor)*
    self.DefaultNodeVisit(node)
    _IncreasePenalty(node, TERM)

    index = 1
    while index < len(node.children) - 1:
      child = node.children[index]
      if pytree_utils.NodeName(child) in self._TERM_OPS:
        next_node = pytree_utils.FirstLeafNode(node.children[index + 1])
        _SetSplitPenalty(next_node, TERM)
      index += 1
Example #15
0
  def Visit_arith_expr(self, node):  # pylint: disable=invalid-name
    # arith_expr ::= term (('+'|'-') term)*
    self.DefaultNodeVisit(node)
    _IncreasePenalty(node, ARITH_EXPR)

    index = 1
    while index < len(node.children) - 1:
      child = node.children[index]
      if pytree_utils.NodeName(child) in self._ARITH_OPS:
        next_node = pytree_utils.FirstLeafNode(node.children[index + 1])
        _SetSplitPenalty(next_node, ARITH_EXPR)
      index += 1
Example #16
0
 def Visit_expr(self, node):  # pylint: disable=invalid-name
   # expr ::= xor_expr ('|' xor_expr)*
   self.DefaultNodeVisit(node)
   _IncreasePenalty(node, EXPR)
   index = 1
   while index < len(node.children) - 1:
     child = node.children[index]
     if isinstance(child, pytree.Leaf) and child.value == '|':
       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'))
     index += 1
    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)
                self._SetNumNewlines(leaf, self._GetNumNewlines(leaf))
        self.last_was_class_or_function = False
        super(_BlankLineCalculator, self).DefaultNodeVisit(node)
Example #18
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, format_token.Subtype.DICT_SET_GENERATOR)
            elif pytree_utils.NodeName(child) in ('COLON', 'DOUBLESTAR'):
                dict_maker = True

        if not comp_for and dict_maker:
            last_was_colon = False
            unpacking = False
            for child in node.children:
                if pytree_utils.NodeName(child) == 'DOUBLESTAR':
                    _AppendFirstLeafTokenSubtype(
                        child, format_token.Subtype.KWARGS_STAR_STAR)
                if last_was_colon:
                    if style.Get('INDENT_DICTIONARY_VALUE'):
                        _InsertPseudoParentheses(child)
                    else:
                        _AppendFirstLeafTokenSubtype(
                            child, format_token.Subtype.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, format_token.Subtype.DICTIONARY_KEY)
                    _AppendSubtypeRec(child,
                                      format_token.Subtype.DICTIONARY_KEY_PART)
                last_was_colon = pytree_utils.NodeName(child) == 'COLON'
                if pytree_utils.NodeName(child) == 'DOUBLESTAR':
                    unpacking = True
                elif last_was_colon:
                    unpacking = False
Example #19
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 == '(':
     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])
Example #20
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))
Example #21
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))
def _StartsInZerothColumn(node):
    return (pytree_utils.FirstLeafNode(node).column == 0
            or (_AsyncFunction(node) and node.prev_sibling.column == 0))
Example #23
0
 def first_leaf_is_comment(node):
     first_leaf = pytree_utils.FirstLeafNode(node)
     return pytree_utils.NodeName(first_leaf) == 'COMMENT'
Example #24
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)
Example #25
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)
Example #26
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':
          # 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
        else:
          break

    # 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:
          subtypes = pytree_utils.GetNodeAnnotation(
              trailer.children[0], pytree_utils.Annotation.SUBTYPE)
          if subtypes and format_token.Subtype.SUBSCRIPT_BRACKET in subtypes:
            _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])