def MustSplit(self): """Returns True if the line must split before the next token.""" current = self.next_token previous = current.previous_token if current.is_pseudo_paren: return False if current.must_break_before: return True if not previous: return False if self.stack[ -1].split_before_closing_bracket and current.value in '}]': # Split before the closing bracket if we can. return current.node_split_penalty != split_penalty.UNBREAKABLE ########################################################################### # List Splitting if (style.Get('DEDENT_CLOSING_BRACKETS') or style.Get('SPLIT_BEFORE_FIRST_ARGUMENT')): bracket = current if current.ClosesScope() else previous if format_token.Subtype.SUBSCRIPT_BRACKET not in bracket.subtypes: if bracket.OpensScope(): if style.Get('COALESCE_BRACKETS'): if current.OpensScope(): # Prefer to keep all opening brackets together. return False if (not _IsLastScopeInLine(bracket) or unwrapped_line.IsSurroundedByBrackets(bracket)): last_token = bracket.matching_bracket else: last_token = _LastTokenInLine(bracket.matching_bracket) if not self._FitsOnLine(bracket, last_token): # Split before the first element if the whole list can't fit on a # single line. self.stack[-1].split_before_closing_bracket = True return True elif style.Get( 'DEDENT_CLOSING_BRACKETS') and current.ClosesScope(): # Split before and dedent the closing bracket. return self.stack[-1].split_before_closing_bracket if (current.is_name or current.is_string) and previous.value == ',': # If the list has function calls in it and the full list itself cannot # fit on the line, then we want to split. Otherwise, we'll get something # like this: # # X = [ # Bar(xxx='some string', # yyy='another long string', # zzz='a third long string'), Bar( # xxx='some string', # yyy='another long string', # zzz='a third long string') # ] # # or when a string formatting syntax. func_call_or_string_format = False if current.is_name: tok = current.next_token while tok and (tok.is_name or tok.value == '.'): tok = tok.next_token func_call_or_string_format = tok.value == '(' elif current.is_string: tok = current.next_token while tok and tok.is_string: tok = tok.next_token func_call_or_string_format = tok.value == '%' if func_call_or_string_format: open_bracket = unwrapped_line.IsSurroundedByBrackets(current) if open_bracket and open_bracket.value in '[{': if not self._FitsOnLine(open_bracket, open_bracket.matching_bracket): return True ########################################################################### # Dict/Set Splitting if (style.Get('EACH_DICT_ENTRY_ON_SEPARATE_LINE') and format_token.Subtype.DICTIONARY_KEY in current.subtypes and not current.is_comment): # Place each dictionary entry onto its own line. if previous.value == '{' and previous.previous_token: opening = _GetOpeningBracket(previous.previous_token) if (opening and opening.value == '(' and opening.previous_token and opening.previous_token.is_name): # This is a dictionary that's an argument to a function. if self._FitsOnLine(previous, previous.matching_bracket): return False return True if (style.Get('SPLIT_BEFORE_DICT_SET_GENERATOR') and format_token.Subtype.DICT_SET_GENERATOR in current.subtypes): # Split before a dict/set generator. return True if (format_token.Subtype.DICTIONARY_VALUE in current.subtypes or (previous.is_pseudo_paren and previous.value == '(' and not current.is_comment)): # Split before the dictionary value if we can't fit every dictionary # entry on its own line. if not current.OpensScope(): opening = _GetOpeningBracket(current) if not self._EachDictEntryFitsOnOneLine(opening): return True if previous.value == '{': # Split if the dict/set cannot fit on one line and ends in a comma. closing = previous.matching_bracket if (not self._FitsOnLine(previous, closing) and closing.previous_token.value == ','): self.stack[-1].split_before_closing_bracket = True return True ########################################################################### # Argument List Splitting if (style.Get('SPLIT_BEFORE_NAMED_ASSIGNS') and not current.is_comment and format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in current.subtypes): if (previous.value not in {'=', ':', '*', '**'} and current.value not in ':=,)' and not _IsFunctionDefinition(previous)): # If we're going to split the lines because of named arguments, then we # want to split after the opening bracket as well. But not when this is # part of a function definition. if previous.value == '(': # Make sure we don't split after the opening bracket if the # continuation indent is greater than the opening bracket: # # a( # b=1, # c=2) if (self._FitsOnLine(previous, previous.matching_bracket) and unwrapped_line.IsSurroundedByBrackets(previous)): # An argument to a function is a function call with named # assigns. return False column = self.column - self.stack[-1].last_space return column > style.Get('CONTINUATION_INDENT_WIDTH') opening = _GetOpeningBracket(current) if opening: arglist_length = (opening.matching_bracket.total_length - opening.total_length + self.stack[-1].indent) return arglist_length > self.column_limit if style.Get('SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED'): # Split before arguments in a function call or definition if the # arguments are terminated by a comma. opening = _GetOpeningBracket(current) if opening and opening.previous_token and opening.previous_token.is_name: if previous.value in '(,': if opening.matching_bracket.previous_token.value == ',': return True if ((current.is_name or current.value in {'*', '**'}) and previous.value == ','): # If we have a function call within an argument list and it won't fit on # the remaining line, but it will fit on a line by itself, then go ahead # and split before the call. opening = _GetOpeningBracket(current) if (opening and opening.value == '(' and opening.previous_token and (opening.previous_token.is_name or opening.previous_token.value in {'*', '**'})): is_func_call = False token = current while token: if token.value == '(': is_func_call = True break if (not (token.is_name or token.value in {'*', '**'}) and token.value != '.'): break token = token.next_token if is_func_call: if not self._FitsOnLine(current, opening.matching_bracket): return True pprevious = previous.previous_token if (current.is_name and pprevious and pprevious.is_name and previous.value == '('): if (not self._FitsOnLine(previous, previous.matching_bracket) and _IsFunctionCallWithArguments(current)): # There is a function call, with more than 1 argument, where the first # argument is itself a function call with arguments. In this specific # case, if we split after the first argument's opening '(', then the # formatting will look bad for the rest of the arguments. E.g.: # # outer_function_call(inner_function_call( # inner_arg1, inner_arg2), # outer_arg1, outer_arg2) # # Instead, enforce a split before that argument to keep things looking # good. return True if (previous.OpensScope() and not current.OpensScope() and format_token.Subtype.SUBSCRIPT_BRACKET not in previous.subtypes): if not current.is_comment: if pprevious and not pprevious.is_keyword and not pprevious.is_name: # We want to split if there's a comment in the container. token = current while token != previous.matching_bracket: if token.is_comment: return True token = token.next_token if previous.value == '(': pptoken = previous.previous_token if not pptoken or not pptoken.is_name: # Split after the opening of a tuple if it doesn't fit on the current # line and it's not a function call. if self._FitsOnLine(previous, previous.matching_bracket): return False elif not self._FitsOnLine(previous, previous.matching_bracket): if (self.column_limit - self.column) / float( self.column_limit) < 0.3: # Try not to squish all of the arguments off to the right. return current.next_token != previous.matching_bracket else: # Split after the opening of a container if it doesn't fit on the # current line or if it has a comment. if not self._FitsOnLine(previous, previous.matching_bracket): return True ########################################################################### # List Comprehension Splitting if (format_token.Subtype.COMP_FOR in current.subtypes and format_token.Subtype.COMP_FOR not in previous.subtypes): # Split at the beginning of a list comprehension. length = _GetLengthOfSubtype(current, format_token.Subtype.COMP_FOR, format_token.Subtype.COMP_IF) if length + self.column > self.column_limit: return True if (format_token.Subtype.COMP_IF in current.subtypes and format_token.Subtype.COMP_IF not in previous.subtypes): # Split at the beginning of an if expression. length = _GetLengthOfSubtype(current, format_token.Subtype.COMP_IF) if length + self.column > self.column_limit: return True ########################################################################### # Original Formatting Splitting # These checks rely upon the original formatting. This is in order to # attempt to keep hand-written code in the same condition as it was before. # However, this may cause the formatter to fail to be idempotent. if (style.Get('SPLIT_BEFORE_BITWISE_OPERATOR') and current.value in '&|' and previous.lineno < current.lineno): # Retain the split before a bitwise operator. return True if (current.is_comment and previous.lineno < current.lineno - current.value.count('\n')): # If a comment comes in the middle of an unwrapped line (like an if # conditional with comments interspersed), then we want to split if the # original comments were on a separate line. return True return False
def _IsArgumentToFunction(token): bracket = unwrapped_line.IsSurroundedByBrackets(token) if not bracket or bracket.value != '(': return False previous = bracket.previous_token return previous and previous.is_name
def MustSplit(self): """Returns True if the line must split before the next token.""" current = self.next_token previous = current.previous_token if current.is_pseudo_paren: return False if current.must_break_before: return True if not previous: return False if style.Get( 'SPLIT_ALL_COMMA_SEPARATED_VALUES') and previous.value == ',': return True if (style.Get('SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES') and previous.value == ','): # Avoid breaking in a container that fits in the current line if possible opening = _GetOpeningBracket(current) # Can't find opening bracket, behave the same way as # SPLIT_ALL_COMMA_SEPARATED_VALUES if not opening: return True # If the container doesn't fit in the current line, must split return not self._ContainerFitsOnStartLine(opening) if (self.stack[-1].split_before_closing_bracket and current.value in '}]' and style.Get('SPLIT_BEFORE_CLOSING_BRACKET')): # Split before the closing bracket if we can. if format_token.Subtype.SUBSCRIPT_BRACKET not in current.subtypes: return current.node_split_penalty != split_penalty.UNBREAKABLE if (current.value == ')' and previous.value == ',' and not _IsSingleElementTuple(current.matching_bracket)): return True # Prevent splitting before the first argument in compound statements # with the exception of function declarations. if (style.Get('SPLIT_BEFORE_FIRST_ARGUMENT') and _IsCompoundStatement(self.line.first) and not _IsFunctionDef(self.line.first)): return False ########################################################################### # List Splitting if (style.Get('DEDENT_CLOSING_BRACKETS') or style.Get('SPLIT_BEFORE_FIRST_ARGUMENT')): bracket = current if current.ClosesScope() else previous if format_token.Subtype.SUBSCRIPT_BRACKET not in bracket.subtypes: if bracket.OpensScope(): if style.Get('COALESCE_BRACKETS'): if current.OpensScope(): # Prefer to keep all opening brackets together. return False if (not _IsLastScopeInLine(bracket) or unwrapped_line.IsSurroundedByBrackets(bracket)): last_token = bracket.matching_bracket else: last_token = _LastTokenInLine(bracket.matching_bracket) if not self._FitsOnLine(bracket, last_token): # Split before the first element if the whole list can't fit on a # single line. self.stack[-1].split_before_closing_bracket = True return True elif style.Get( 'DEDENT_CLOSING_BRACKETS') and current.ClosesScope(): # Split before and dedent the closing bracket. return self.stack[-1].split_before_closing_bracket if (style.Get('SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN') and current.is_name): # An expression that's surrounded by parens gets split after the opening # parenthesis. def SurroundedByParens(token): """Check if it's an expression surrounded by parentheses.""" while token: if token.value == ',': return False if token.value == ')': return not token.next_token if token.OpensScope(): token = token.matching_bracket.next_token else: token = token.next_token return False if (previous.value == '(' and not previous.is_pseudo_paren and not unwrapped_line.IsSurroundedByBrackets(previous)): pptoken = previous.previous_token if (pptoken and not pptoken.is_name and not pptoken.is_keyword and SurroundedByParens(current)): return True if (current.is_name or current.is_string) and previous.value == ',': # If the list has function calls in it and the full list itself cannot # fit on the line, then we want to split. Otherwise, we'll get something # like this: # # X = [ # Bar(xxx='some string', # yyy='another long string', # zzz='a third long string'), Bar( # xxx='some string', # yyy='another long string', # zzz='a third long string') # ] # # or when a string formatting syntax. func_call_or_string_format = False tok = current.next_token if current.is_name: while tok and (tok.is_name or tok.value == '.'): tok = tok.next_token func_call_or_string_format = tok and tok.value == '(' elif current.is_string: while tok and tok.is_string: tok = tok.next_token func_call_or_string_format = tok and tok.value == '%' if func_call_or_string_format: open_bracket = unwrapped_line.IsSurroundedByBrackets(current) if open_bracket: if open_bracket.value in '[{': if not self._FitsOnLine(open_bracket, open_bracket.matching_bracket): return True elif tok.value == '(': if not self._FitsOnLine(current, tok.matching_bracket): return True if (current.OpensScope() and previous.value == ',' and format_token.Subtype.DICTIONARY_KEY not in current.next_token.subtypes): # If we have a list of tuples, then we can get a similar look as above. If # the full list cannot fit on the line, then we want a split. open_bracket = unwrapped_line.IsSurroundedByBrackets(current) if (open_bracket and open_bracket.value in '[{' and format_token.Subtype.SUBSCRIPT_BRACKET not in open_bracket.subtypes): if not self._FitsOnLine(current, current.matching_bracket): return True ########################################################################### # Dict/Set Splitting if (style.Get('EACH_DICT_ENTRY_ON_SEPARATE_LINE') and format_token.Subtype.DICTIONARY_KEY in current.subtypes and not current.is_comment): # Place each dictionary entry onto its own line. if previous.value == '{' and previous.previous_token: opening = _GetOpeningBracket(previous.previous_token) if (opening and opening.value == '(' and opening.previous_token and opening.previous_token.is_name): # This is a dictionary that's an argument to a function. if (self._FitsOnLine(previous, previous.matching_bracket) and previous.matching_bracket.next_token and (not opening.matching_bracket.next_token or opening.matching_bracket.next_token.value != '.') and _ScopeHasNoCommas(previous)): # Don't split before the key if: # - The dictionary fits on a line, and # - The function call isn't part of a builder-style call and # - The dictionary has one entry and no trailing comma return False return True if (style.Get('SPLIT_BEFORE_DICT_SET_GENERATOR') and format_token.Subtype.DICT_SET_GENERATOR in current.subtypes): # Split before a dict/set generator. return True if (format_token.Subtype.DICTIONARY_VALUE in current.subtypes or (previous.is_pseudo_paren and previous.value == '(' and not current.is_comment)): # Split before the dictionary value if we can't fit every dictionary # entry on its own line. if not current.OpensScope(): opening = _GetOpeningBracket(current) if not self._EachDictEntryFitsOnOneLine(opening): return style.Get('ALLOW_SPLIT_BEFORE_DICT_VALUE') if previous.value == '{': # Split if the dict/set cannot fit on one line and ends in a comma. closing = previous.matching_bracket if (not self._FitsOnLine(previous, closing) and closing.previous_token.value == ','): self.stack[-1].split_before_closing_bracket = True return True ########################################################################### # Argument List Splitting if (style.Get('SPLIT_BEFORE_NAMED_ASSIGNS') and not current.is_comment and format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in current.subtypes): if (previous.value not in {'=', ':', '*', '**'} and current.value not in ':=,)' and not _IsFunctionDefinition(previous)): # If we're going to split the lines because of named arguments, then we # want to split after the opening bracket as well. But not when this is # part of a function definition. if previous.value == '(': # Make sure we don't split after the opening bracket if the # continuation indent is greater than the opening bracket: # # a( # b=1, # c=2) if (self._FitsOnLine(previous, previous.matching_bracket) and unwrapped_line.IsSurroundedByBrackets(previous)): # An argument to a function is a function call with named # assigns. return False # Don't split if not required if (not style.Get( 'SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN') and not style.Get('SPLIT_BEFORE_FIRST_ARGUMENT')): return False column = self.column - self.stack[-1].last_space return column > style.Get('CONTINUATION_INDENT_WIDTH') opening = _GetOpeningBracket(current) if opening: return not self._ContainerFitsOnStartLine(opening) if (current.value not in '{)' and previous.value == '(' and self._ArgumentListHasDictionaryEntry(current)): return True if style.Get('SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED'): # Split before arguments in a function call or definition if the # arguments are terminated by a comma. opening = _GetOpeningBracket(current) if opening and opening.previous_token and opening.previous_token.is_name: if previous.value in '(,': if opening.matching_bracket.previous_token.value == ',': return True if ((current.is_name or current.value in {'*', '**'}) and previous.value == ','): # If we have a function call within an argument list and it won't fit on # the remaining line, but it will fit on a line by itself, then go ahead # and split before the call. opening = _GetOpeningBracket(current) if (opening and opening.value == '(' and opening.previous_token and (opening.previous_token.is_name or opening.previous_token.value in {'*', '**'})): is_func_call = False opening = current while opening: if opening.value == '(': is_func_call = True break if (not (opening.is_name or opening.value in {'*', '**'}) and opening.value != '.'): break opening = opening.next_token if is_func_call: if (not self._FitsOnLine(current, opening.matching_bracket) or (opening.matching_bracket.next_token and opening.matching_bracket.next_token.value != ',' and not opening.matching_bracket.next_token.ClosesScope()) ): return True pprevious = previous.previous_token # A function call with a dictionary as its first argument may result in # unreadable formatting if the dictionary spans multiple lines. The # dictionary itself is formatted just fine, but the remaning arguments are # indented too far: # # function_call({ # KEY_1: 'value one', # KEY_2: 'value two', # }, # default=False) if (current.value == '{' and previous.value == '(' and pprevious and pprevious.is_name): dict_end = current.matching_bracket next_token = dict_end.next_token if next_token.value == ',' and not self._FitsOnLine( current, dict_end): return True if (current.is_name and pprevious and pprevious.is_name and previous.value == '('): if (not self._FitsOnLine(previous, previous.matching_bracket) and _IsFunctionCallWithArguments(current)): # There is a function call, with more than 1 argument, where the first # argument is itself a function call with arguments that does not fit # into the line. In this specific case, if we split after the first # argument's opening '(', then the formatting will look bad for the # rest of the arguments. E.g.: # # outer_function_call(inner_function_call( # inner_arg1, inner_arg2), # outer_arg1, outer_arg2) # # Instead, enforce a split before that argument to keep things looking # good. if (style.Get('SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN') or style.Get('SPLIT_BEFORE_FIRST_ARGUMENT')): return True opening = _GetOpeningBracket(current) if (opening and opening.value == '(' and opening.previous_token and (opening.previous_token.is_name or opening.previous_token.value in {'*', '**'})): is_func_call = False opening = current while opening: if opening.value == '(': is_func_call = True break if (not (opening.is_name or opening.value in {'*', '**'}) and opening.value != '.'): break opening = opening.next_token if is_func_call: if (not self._FitsOnLine(current, opening.matching_bracket) or (opening.matching_bracket.next_token and opening.matching_bracket.next_token.value != ',' and not opening.matching_bracket.next_token. ClosesScope())): return True if (previous.OpensScope() and not current.OpensScope() and not current.is_comment and format_token.Subtype.SUBSCRIPT_BRACKET not in previous.subtypes): if pprevious and not pprevious.is_keyword and not pprevious.is_name: # We want to split if there's a comment in the container. token = current while token != previous.matching_bracket: if token.is_comment: return True token = token.next_token if previous.value == '(': pptoken = previous.previous_token if not pptoken or not pptoken.is_name: # Split after the opening of a tuple if it doesn't fit on the current # line and it's not a function call. if self._FitsOnLine(previous, previous.matching_bracket): return False elif not self._FitsOnLine(previous, previous.matching_bracket): if len(previous.container_elements) == 1: return False elements = previous.container_elements + [ previous.matching_bracket ] i = 1 while i < len(elements): if (not elements[i - 1].OpensScope() and not self._FitsOnLine( elements[i - 1], elements[i])): return True i += 1 if (self.column_limit - self.column) / float( self.column_limit) < 0.3: # Try not to squish all of the arguments off to the right. return True else: # Split after the opening of a container if it doesn't fit on the # current line. if not self._FitsOnLine(previous, previous.matching_bracket): return True ########################################################################### # Original Formatting Splitting # These checks rely upon the original formatting. This is in order to # attempt to keep hand-written code in the same condition as it was before. # However, this may cause the formatter to fail to be idempotent. if (style.Get('SPLIT_BEFORE_BITWISE_OPERATOR') and current.value in '&|' and previous.lineno < current.lineno): # Retain the split before a bitwise operator. return True if (current.is_comment and previous.lineno < current.lineno - current.value.count('\n')): # If a comment comes in the middle of an unwrapped line (like an if # conditional with comments interspersed), then we want to split if the # original comments were on a separate line. return True return False
def MustSplit(self): """Returns True if the line must split before the next token.""" current = self.next_token previous = current.previous_token column_limit = style.Get('COLUMN_LIMIT') if current.must_break_before: return True if previous and style.Get('DEDENT_CLOSING_BRACKETS'): bracket = current if current.ClosesScope() else previous if format_token.Subtype.SUBSCRIPT_BRACKET not in bracket.subtypes: if bracket.OpensScope(): if (unwrapped_line.IsSurroundedByBrackets(bracket) or not _IsLastScopeInLine(bracket)): last_token = bracket.matching_bracket else: last_token = _LastTokenInLine(bracket.matching_bracket) length = last_token.total_length - bracket.total_length if length + self.column >= column_limit: return True elif current.ClosesScope(): opening = bracket.matching_bracket if (unwrapped_line.IsSurroundedByBrackets(opening) or not _IsLastScopeInLine(bracket) or bracket.next_token is None): last_token = bracket else: last_token = _LastTokenInLine(bracket.next_token) length = last_token.total_length - opening.total_length if length + opening.column >= column_limit: return True if (self.stack[-1].split_before_closing_bracket and # FIXME(morbo): Use the 'matching_bracket' instead of this. # FIXME(morbo): Don't forget about tuples! current.value in ']}'): # Split if we need to split before the closing bracket and the next # token is a closing bracket. return current.node_split_penalty != split_penalty.UNBREAKABLE if not previous: return False # TODO(morbo): This should be controlled with a knob. if (format_token.Subtype.DICTIONARY_KEY in current.subtypes and not current.is_comment): # Place each dictionary entry on its own line. return True # TODO(morbo): This should be controlled with a knob. if format_token.Subtype.DICT_SET_GENERATOR in current.subtypes: return True if (style.Get('SPLIT_BEFORE_NAMED_ASSIGNS') and format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in current.subtypes): if (previous.value not in {'(', '=', '*', '**'} and current.value not in '=,)'): opening = _GetOpeningParen(current) if opening: arglist_length = (opening.matching_bracket.total_length - opening.total_length + self.column) return arglist_length > column_limit if (previous.value in '{[' and current.lineno != previous.lineno and format_token.Subtype.SUBSCRIPT_BRACKET not in previous.subtypes): return True if (previous.value == ':' and _IsDictionaryValue(current) and current.lineno != previous.lineno): # Retain the split between the dictionary key and value. return True if (format_token.Subtype.COMP_FOR in current.subtypes and format_token.Subtype.COMP_FOR not in previous.subtypes): length = _GetLengthOfSubtype(current, format_token.Subtype.COMP_FOR, format_token.Subtype.COMP_IF) if length + self.column > column_limit: return True if (format_token.Subtype.COMP_IF in current.subtypes and format_token.Subtype.COMP_IF not in previous.subtypes): length = _GetLengthOfSubtype(current, format_token.Subtype.COMP_IF) if length + self.column > column_limit: return True previous_previous_token = previous.previous_token if (current.name == 'NAME' and previous_previous_token and previous_previous_token.name == 'NAME' and not previous_previous_token.is_keyword and previous.value == '('): sibling = previous.node.next_sibling if pytree_utils.NodeName(sibling) == 'arglist': arglist = previous.node.next_sibling if len(arglist.children) > 2: if _IsFunctionCallWithArguments(current): # There is a function call, with more than 1 argument, where # the first argument is itself a function call with arguments. # In this specific case, if we split after the first argument's # opening '(', then the formatting will look bad for the rest # of the arguments. Instead, enforce a split before that # argument to keep things looking good. return True elif (current.OpensScope() and current.matching_bracket.total_length + self.column > column_limit): # There is a data literal that will need to be split and could mess # up the formatting. return True if (style.Get('SPLIT_BEFORE_BITWISE_OPERATOR') and current.value in '&|' and previous.lineno < current.lineno): return True if (current.is_comment and previous.lineno < current.lineno - current.value.count('\n')): # If a comment comes in the middle of an unwrapped line (like an if # conditional with comments interspersed), then we want to split if the # original comments were on a separate line. return True return False
def MustSplit(self): """Returns True if the line must split before the next token.""" current = self.next_token previous = current.previous_token if current.is_pseudo_paren: return False if current.must_break_before: return True if (previous and (style.Get('DEDENT_CLOSING_BRACKETS') or style.Get('SPLIT_BEFORE_FIRST_ARGUMENT'))): bracket = current if current.ClosesScope() else previous if format_token.Subtype.SUBSCRIPT_BRACKET not in bracket.subtypes: if bracket.OpensScope(): if style.Get('COALESCE_BRACKETS'): if current.OpensScope(): return False if (not _IsLastScopeInLine(bracket) or unwrapped_line.IsSurroundedByBrackets(bracket)): last_token = bracket.matching_bracket else: last_token = _LastTokenInLine(bracket.matching_bracket) if not self._FitsOnLine(bracket, last_token): self.stack[-1].split_before_closing_bracket = True return True elif style.Get( 'DEDENT_CLOSING_BRACKETS') and current.ClosesScope(): return self.stack[-1].split_before_closing_bracket if self.stack[ -1].split_before_closing_bracket and current.value in '}]': # Split if we need to split before the closing bracket. return current.node_split_penalty != split_penalty.UNBREAKABLE if not previous: return False # TODO(morbo): This should be controlled with a knob. if (format_token.Subtype.DICTIONARY_KEY in current.subtypes and not current.is_comment): # Place each dictionary entry on its own line. if previous.value == '{' and previous.previous_token: opening = _GetOpeningBracket(previous.previous_token) if (opening and opening.value == '(' and opening.previous_token and opening.previous_token.is_name): # This is a dictionary that's an argument to a function. if self._FitsOnLine(previous, previous.matching_bracket): return False return True # TODO(morbo): This should be controlled with a knob. if format_token.Subtype.DICT_SET_GENERATOR in current.subtypes: return True if (style.Get('SPLIT_BEFORE_NAMED_ASSIGNS') and not current.is_comment and format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in current.subtypes): if (previous.value not in {'=', ':', '*', '**'} and current.value not in ':=,)'): # If we're going to split the lines because of named arguments, then we # want to split after the opening bracket as well. But not when this is # part of function definition. if not _IsFunctionDefinition(previous): # Make sure we don't split after the opening bracket if the # continuation indent is greater than the opening bracket: # # a( # b=1, # c=2) indent_amt = self.stack[-1].indent * style.Get( 'INDENT_WIDTH') pptoken = previous.previous_token opening_column = len( pptoken.value) if pptoken else 0 - indent_amt - 1 if previous.value == '(': return opening_column >= style.Get( 'CONTINUATION_INDENT_WIDTH') opening = _GetOpeningBracket(current) if opening: arglist_length = ( opening.matching_bracket.total_length - opening.total_length + self.stack[-1].indent) return arglist_length > self.column_limit if style.Get('SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED'): # Split before arguments in a function call or definition if the # arguments are terminated by a comma. opening = _GetOpeningBracket(current) if opening and opening.previous_token and opening.previous_token.is_name: if previous.value in '(,': if opening.matching_bracket.previous_token.value == ',': return True if (format_token.Subtype.DICTIONARY_VALUE in current.subtypes or (previous.is_pseudo_paren and previous.value == '(')): if not current.OpensScope(): opening = _GetOpeningBracket(current) if previous.is_pseudo_paren: # Split before the dictionary value if we can't fit the whole # dictionary on one line. if not self._EachDictEntryFitsOnOneLine(opening): return True if (previous.OpensScope() and not current.OpensScope() and format_token.Subtype.SUBSCRIPT_BRACKET not in previous.subtypes): if not current.is_comment: pprevious = previous.previous_token if pprevious and not pprevious.is_keyword and not pprevious.is_name: # We want to split if there's a comment in the container. token = current while token != previous.matching_bracket: if token.is_comment: return True token = token.next_token if previous.value == '(': pptoken = previous.previous_token if not pptoken or not pptoken.is_name: # Split after the opening of a tuple if it doesn't fit on the current # line and it's not a function call. if self._FitsOnLine(previous, previous.matching_bracket): return False else: # Split after the opening of a container if it doesn't fit on the # current line or if it has a comment. if not self._FitsOnLine(previous, previous.matching_bracket): return True if previous.value == '{': closing = previous.matching_bracket if (not self._FitsOnLine(previous, closing) and closing.previous_token.value == ','): self.stack[-1].split_before_closing_bracket = True return True if (format_token.Subtype.COMP_FOR in current.subtypes and format_token.Subtype.COMP_FOR not in previous.subtypes): # Split at the beginning of a list comprehension. length = _GetLengthOfSubtype(current, format_token.Subtype.COMP_FOR, format_token.Subtype.COMP_IF) if length + self.column > self.column_limit: return True if (format_token.Subtype.COMP_IF in current.subtypes and format_token.Subtype.COMP_IF not in previous.subtypes): # Split at the beginning of an if expression. length = _GetLengthOfSubtype(current, format_token.Subtype.COMP_IF) if length + self.column > self.column_limit: return True previous_previous_token = previous.previous_token if (current.is_name and previous_previous_token and previous_previous_token.is_name and previous.value == '('): if not self._FitsOnLine(previous, previous.matching_bracket): if _IsFunctionCallWithArguments(current): # There is a function call, with more than 1 argument, where # the first argument is itself a function call with arguments. # In this specific case, if we split after the first argument's # opening '(', then the formatting will look bad for the rest # of the arguments. Instead, enforce a split before that # argument to keep things looking good. return True elif current.OpensScope(): if not self._FitsOnLine(current, current.matching_bracket): # There is a data literal that will need to be split and could mess # up the formatting. return True if (style.Get('SPLIT_BEFORE_BITWISE_OPERATOR') and current.value in '&|' and previous.lineno < current.lineno): # Retain the split before a bitwise operator. return True if (current.is_comment and previous.lineno < current.lineno - current.value.count('\n')): # If a comment comes in the middle of an unwrapped line (like an if # conditional with comments interspersed), then we want to split if the # original comments were on a separate line. return True if current.is_name and previous.value == ',': # If we have a function call within an argument list and it won't fit on # the remaining line, but it will fit on a line by itself, then go ahead # and split before the call. opening = _GetOpeningBracket(current) if (opening and opening.value == '(' and opening.previous_token and opening.previous_token.is_name): is_func_call = False token = current while token: if token.value == '(': is_func_call = True break if not token.is_name and token.value != '.': break token = token.next_token if is_func_call: if not self._FitsOnLine(current, opening.matching_bracket): return True return False