Пример #1
0
 def Visit_funcdef(self, node):  # pylint: disable=invalid-name
   # funcdef ::= 'def' NAME parameters ['->' test] ':' suite
   #
   # Can't break before the function name and before the colon. The parameters
   # are handled by child iteration.
   colon_idx = 1
   while pytree_utils.NodeName(node.children[colon_idx]) == 'simple_stmt':
     colon_idx += 1
   _SetUnbreakable(node.children[colon_idx])
   arrow_idx = -1
   while colon_idx < len(node.children):
     if isinstance(node.children[colon_idx], pytree.Leaf):
       if node.children[colon_idx].value == ':':
         break
       if node.children[colon_idx].value == '->':
         arrow_idx = colon_idx
     colon_idx += 1
   _SetUnbreakable(node.children[colon_idx])
   self.DefaultNodeVisit(node)
   if arrow_idx > 0:
     _SetSplitPenalty(
         pytree_utils.LastLeafNode(node.children[arrow_idx - 1]), 0)
     _SetUnbreakable(node.children[arrow_idx])
     _SetStronglyConnected(node.children[arrow_idx + 1])
Пример #2
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])
Пример #3
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 (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)

          # 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)
Пример #4
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 == 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 == 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(token.LPAR,
                         u'(',
                         context=('', (first.get_lineno(), first.column - 1)))
    last_lineno = last.get_lineno()
    if last.type == token.STRING and '\n' in last.value:
        last_lineno += last.value.count('\n')

    if last.type == 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(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,
                                     format_token.Subtype.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,
                                     format_token.Subtype.DICTIONARY_VALUE)