Performance enhancements
- Cache values
- Perform expensive checks last
diff --git a/CHANGELOG b/CHANGELOG
index 86da9b7..72a1609 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,10 @@
# All notable changes to this project will be documented in this file.
# This project adheres to [Semantic Versioning](http://semver.org/).
+## [0.9.1] UNRELEASED
+### Changed
+- Performance enhancements.
+
## [0.9.0] 2016-05-29
### Added
- Added a knob (SPLIT_PENALTY_BEFORE_IF_EXPR) to adjust the split penalty
diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py
index 04e3deb..d0b5eb4 100644
--- a/yapf/yapflib/comment_splicer.py
+++ b/yapf/yapflib/comment_splicer.py
@@ -69,7 +69,6 @@
# We can't just insert it before the NEWLINE node, because as a
# result of the way pytrees are organized, this node can be under
# an inappropriate parent.
- assert prev_leaf[0] is not None
comment_column -= len(comment_prefix)
comment_column += len(comment_prefix) - len(comment_prefix.lstrip())
pytree_utils.InsertNodesAfter(
diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py
index 137f6be..c4407c6 100644
--- a/yapf/yapflib/format_decision_state.py
+++ b/yapf/yapflib/format_decision_state.py
@@ -134,8 +134,8 @@
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)):
+ if (not _IsLastScopeInLine(bracket) or
+ unwrapped_line.IsSurroundedByBrackets(bracket)):
last_token = bracket.matching_bracket
else:
last_token = _LastTokenInLine(bracket.matching_bracket)
@@ -329,15 +329,6 @@
self.start_of_line_level = self.paren_level
self.lowest_level_on_line = self.paren_level
- # Any break on this level means that the parent level has been broken and we
- # need to avoid bin packing there.
- for paren_state in self.stack:
- paren_state.split_before_parameter = True
-
- if (previous.value != ',' and not previous.is_binary_op and
- not current.is_binary_op and not previous.OpensScope()):
- self.stack[-1].split_before_parameter = True
-
if (previous.OpensScope() or (previous.is_comment and
previous.previous_token is not None and
previous.previous_token.OpensScope())):
@@ -387,12 +378,12 @@
return top_of_stack.closing_scope_indent
if (previous and previous.is_string and current.is_string and
- _IsDictionaryValue(current)):
+ format_token.Subtype.DICTIONARY_VALUE in current.subtypes):
return previous.column
if style.Get('INDENT_DICTIONARY_VALUE'):
- if _IsDictionaryValue(current):
- if previous and (previous.value == ':' or previous.is_pseudo_paren):
+ if previous and (previous.value == ':' or previous.is_pseudo_paren):
+ if format_token.Subtype.DICTIONARY_VALUE in current.subtypes:
return top_of_stack.indent
if (self.line.first.value in _COMPOUND_STMTS and
@@ -526,7 +517,6 @@
split_before_closing_bracket: Whether a newline needs to be inserted before
the closing bracket. We only want to insert a newline before the closing
bracket if there also was a newline after the beginning left bracket.
- split_before_parameter: Split the line after the next comma.
num_line_splits: Number of line splits this _ParenState contains already.
Each subsequent line split gets an increasing penalty.
"""
@@ -538,9 +528,15 @@
self.last_space = last_space
self.closing_scope_indent = 0
self.split_before_closing_bracket = False
- self.split_before_parameter = False
self.num_line_splits = 0
+ def __copy__(self):
+ state = _ParenState(self.indent, self.last_space)
+ state.closing_scope_indent = self.closing_scope_indent
+ state.split_before_closing_bracket = self.split_before_closing_bracket
+ self.num_line_splits = self.num_line_splits
+ return state
+
def __repr__(self):
return '[indent::%d, last_space::%d, closing_scope_indent::%d]' % (
self.indent, self.last_space, self.closing_scope_indent)
diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py
index d593d01..35de91e 100644
--- a/yapf/yapflib/format_token.py
+++ b/yapf/yapflib/format_token.py
@@ -22,6 +22,7 @@
from lib2to3 import pytree
from lib2to3.pgen2 import token
+from yapf.yapflib import py3compat
from yapf.yapflib import pytree_utils
from yapf.yapflib import style
@@ -85,8 +86,7 @@
Arguments:
node: (pytree.Leaf) The node that's being wrapped.
"""
- assert isinstance(node, pytree.Leaf)
- self._node = node
+ self.node = node
self.next_token = None
self.previous_token = None
self.matching_bracket = None
@@ -116,7 +116,7 @@
if self.is_comment:
comment_lines = [s.lstrip() for s in self.value.splitlines()]
- self._node.value = ('\n' + spaces_before).join(comment_lines)
+ self.node.value = ('\n' + spaces_before).join(comment_lines)
if not self.whitespace_prefix:
self.whitespace_prefix = (
@@ -167,108 +167,106 @@
def ClosesScope(self):
return self.value in pytree_utils.CLOSING_BRACKETS
- def GetPytreeNode(self):
- return self._node
-
- @property
- def value(self):
- if self.is_continuation:
- return self._node.value.rstrip()
- return self._node.value
-
- @property
- def node(self):
- return self._node
-
- @property
- def node_split_penalty(self):
- """Split penalty attached to the pytree node of this token.
-
- Returns:
- The penalty, or None if no annotation is attached.
- """
- return pytree_utils.GetNodeAnnotation(self._node,
- pytree_utils.Annotation.SPLIT_PENALTY,
- default=0)
-
- @property
- def newlines(self):
- """The number of newlines needed before this token."""
- return pytree_utils.GetNodeAnnotation(self._node,
- pytree_utils.Annotation.NEWLINES)
-
- @property
- def must_split(self):
- """Return true if the token requires a split before it."""
- return pytree_utils.GetNodeAnnotation(self._node,
- pytree_utils.Annotation.MUST_SPLIT)
-
- @property
- def column(self):
- """The original column number of the node in the source."""
- return self._node.column
-
- @property
- def lineno(self):
- """The original line number of the node in the source."""
- return self._node.lineno
-
- @property
- def subtypes(self):
- """Extra type information for directing formatting."""
- value = pytree_utils.GetNodeAnnotation(self._node,
- pytree_utils.Annotation.SUBTYPE)
- return [Subtype.NONE] if value is None else value
-
- @property
- def is_binary_op(self):
- """Token is a binary operator."""
- return Subtype.BINARY_OPERATOR in self.subtypes
-
- @property
- def name(self):
- """A string representation of the node's name."""
- return pytree_utils.NodeName(self._node)
-
def __repr__(self):
msg = 'FormatToken(name={0}, value={1}'.format(self.name, self.value)
msg += ', pseudo)' if self.is_pseudo_paren else ')'
return msg
@property
+ def value(self):
+ if self.is_continuation:
+ return self.node.value.rstrip()
+ return self.node.value
+
+ @property
+ @py3compat.lru_cache()
+ def node_split_penalty(self):
+ """Split penalty attached to the pytree node of this token."""
+ return pytree_utils.GetNodeAnnotation(self.node,
+ pytree_utils.Annotation.SPLIT_PENALTY,
+ default=0)
+
+ @property
+ def newlines(self):
+ """The number of newlines needed before this token."""
+ return pytree_utils.GetNodeAnnotation(self.node,
+ pytree_utils.Annotation.NEWLINES)
+
+ @property
+ def must_split(self):
+ """Return true if the token requires a split before it."""
+ return pytree_utils.GetNodeAnnotation(self.node,
+ pytree_utils.Annotation.MUST_SPLIT)
+
+ @property
+ def column(self):
+ """The original column number of the node in the source."""
+ return self.node.column
+
+ @property
+ def lineno(self):
+ """The original line number of the node in the source."""
+ return self.node.lineno
+
+ @property
+ @py3compat.lru_cache()
+ def subtypes(self):
+ """Extra type information for directing formatting."""
+ value = pytree_utils.GetNodeAnnotation(self.node,
+ pytree_utils.Annotation.SUBTYPE)
+ return [Subtype.NONE] if value is None else value
+
+ @property
+ @py3compat.lru_cache()
+ def is_binary_op(self):
+ """Token is a binary operator."""
+ return Subtype.BINARY_OPERATOR in self.subtypes
+
+ @property
+ @py3compat.lru_cache()
+ def name(self):
+ """A string representation of the node's name."""
+ return pytree_utils.NodeName(self.node)
+
+ @property
def is_comment(self):
- return self._node.type == token.COMMENT
+ return self.node.type == token.COMMENT
@property
def is_continuation(self):
- return self._node.type == CONTINUATION
+ return self.node.type == CONTINUATION
@property
+ @py3compat.lru_cache()
def is_keyword(self):
return keyword.iskeyword(self.value)
@property
+ @py3compat.lru_cache()
def is_name(self):
- return self._node.type == token.NAME and not self.is_keyword
+ return self.node.type == token.NAME and not self.is_keyword
@property
def is_number(self):
- return self._node.type == token.NUMBER
+ return self.node.type == token.NUMBER
@property
def is_string(self):
- return self._node.type == token.STRING
+ return self.node.type == token.STRING
@property
+ @py3compat.lru_cache()
def is_multiline_string(self):
return (self.is_string and
re.match(r'^[uUbB]?[rR]?(?P<delim>"""|\'\'\').*(?P=delim)$',
self.value, re.DOTALL) is not None)
@property
+ @py3compat.lru_cache()
def is_docstring(self):
return self.is_multiline_string and not self.node.prev_sibling
@property
+ @py3compat.lru_cache()
def is_pseudo_paren(self):
- return hasattr(self._node, 'is_pseudo') and self._node.is_pseudo
+ return hasattr(self.node, 'is_pseudo') and self.node.is_pseudo
diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py
index 231d038..c19cab0 100644
--- a/yapf/yapflib/py3compat.py
+++ b/yapf/yapflib/py3compat.py
@@ -25,6 +25,9 @@
import codecs
open_with_encoding = codecs.open
+ import functools
+ lru_cache = functools.lru_cache
+
range = range
ifilter = filter
raw_input = input
@@ -41,6 +44,14 @@
open_with_encoding = io.open
+ # Python 2.7 doesn't have a native LRU cache, so do nothing.
+ def lru_cache(maxsize=128, typed=False):
+
+ def fake_wrapper(user_function):
+ return user_function
+
+ return fake_wrapper
+
range = xrange
from itertools import ifilter
diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py
index 44c6511..8386693 100644
--- a/yapf/yapflib/pytree_unwrapper.py
+++ b/yapf/yapflib/pytree_unwrapper.py
@@ -107,6 +107,17 @@
_AdjustSplitPenalty(self._cur_unwrapped_line)
self._cur_unwrapped_line = unwrapped_line.UnwrappedLine(self._cur_depth)
+ _STMT_TYPES = frozenset({
+ 'if_stmt',
+ 'while_stmt',
+ 'for_stmt',
+ 'try_stmt',
+ 'expect_clause',
+ 'with_stmt',
+ 'funcdef',
+ 'classdef',
+ })
+
# pylint: disable=invalid-name,missing-docstring
def Visit_simple_stmt(self, node):
# A 'simple_stmt' conveniently represents a non-compound Python statement,
@@ -119,17 +130,9 @@
# standalone comment and in the case of it coming directly after the
# funcdef, it is a "top" comment for the whole function.
# TODO(eliben): add more relevant compound statements here.
- single_stmt_suite = (node.parent and pytree_utils.NodeName(node.parent) in {
- 'if_stmt',
- 'while_stmt',
- 'for_stmt',
- 'try_stmt',
- 'expect_clause',
- 'with_stmt',
- 'funcdef',
- 'classdef',
- })
- is_comment_stmt = pytree_utils.NodeName(node.children[0]) == 'COMMENT'
+ single_stmt_suite = (node.parent and
+ pytree_utils.NodeName(node.parent) in self._STMT_TYPES)
+ is_comment_stmt = pytree_utils.IsCommentStatement(node)
if single_stmt_suite and not is_comment_stmt:
self._cur_depth += 1
self._StartNewLine()
@@ -159,23 +162,35 @@
self._StartNewLine()
self.Visit(child)
+ _IF_STMT_ELEMS = frozenset({'if', 'else', 'elif'})
+
def Visit_if_stmt(self, node): # pylint: disable=invalid-name
- self._VisitCompoundStatement(node, {'if', 'else', 'elif'})
+ self._VisitCompoundStatement(node, self._IF_STMT_ELEMS)
+
+ _WHILE_STMT_ELEMS = frozenset({'while', 'else'})
def Visit_while_stmt(self, node): # pylint: disable=invalid-name
- self._VisitCompoundStatement(node, {'while', 'else'})
+ self._VisitCompoundStatement(node, self._WHILE_STMT_ELEMS)
+
+ _FOR_STMT_ELEMS = frozenset({'for', 'else'})
def Visit_for_stmt(self, node): # pylint: disable=invalid-name
- self._VisitCompoundStatement(node, {'for', 'else'})
+ self._VisitCompoundStatement(node, self._FOR_STMT_ELEMS)
+
+ _TRY_STMT_ELEMS = frozenset({'try', 'except', 'else', 'finally'})
def Visit_try_stmt(self, node): # pylint: disable=invalid-name
- self._VisitCompoundStatement(node, {'try', 'except', 'else', 'finally'})
+ self._VisitCompoundStatement(node, self._TRY_STMT_ELEMS)
+
+ _EXCEPT_STMT_ELEMS = frozenset({'except'})
def Visit_except_clause(self, node): # pylint: disable=invalid-name
- self._VisitCompoundStatement(node, {'except'})
+ self._VisitCompoundStatement(node, self._EXCEPT_STMT_ELEMS)
+
+ _FUNC_DEF_ELEMS = frozenset({'def'})
def Visit_funcdef(self, node): # pylint: disable=invalid-name
- self._VisitCompoundStatement(node, {'def'})
+ self._VisitCompoundStatement(node, self._FUNC_DEF_ELEMS)
def Visit_async_funcdef(self, node): # pylint: disable=invalid-name
self._StartNewLine()
@@ -183,8 +198,10 @@
for child in node.children[1].children:
self.Visit(child)
+ _CLASS_DEF_ELEMS = frozenset({'class'})
+
def Visit_classdef(self, node): # pylint: disable=invalid-name
- self._VisitCompoundStatement(node, {'class'})
+ self._VisitCompoundStatement(node, self._CLASS_DEF_ELEMS)
def Visit_async_stmt(self, node): # pylint: disable=invalid-name
self._StartNewLine()
@@ -202,8 +219,10 @@
self._StartNewLine()
self.Visit(child)
+ _WITH_STMT_ELEMS = frozenset({'with'})
+
def Visit_with_stmt(self, node): # pylint: disable=invalid-name
- self._VisitCompoundStatement(node, {'with'})
+ self._VisitCompoundStatement(node, self._WITH_STMT_ELEMS)
def Visit_suite(self, node): # pylint: disable=invalid-name
# A 'suite' starts a new indentation level in Python.
@@ -273,7 +292,6 @@
if token.value in pytree_utils.OPENING_BRACKETS:
bracket_stack.append(token)
elif token.value in pytree_utils.CLOSING_BRACKETS:
- assert _BRACKET_MATCH[token.value] == bracket_stack[-1].value
bracket_stack[-1].matching_bracket = token
token.matching_bracket = bracket_stack[-1]
bracket_stack.pop()
@@ -291,7 +309,7 @@
bracket_level = 0
for index, token in enumerate(uwline.tokens):
if index and not bracket_level:
- pytree_utils.SetNodeAnnotation(token.GetPytreeNode(),
+ pytree_utils.SetNodeAnnotation(token.node,
pytree_utils.Annotation.SPLIT_PENALTY,
split_penalty.UNBREAKABLE)
if token.value in pytree_utils.OPENING_BRACKETS:
@@ -311,7 +329,7 @@
child = node.children[index]
if isinstance(child, pytree.Leaf) and child.value == ',':
next_child = node.children[index + 1]
- if pytree_utils.NodeName(next_child) == 'COMMENT':
+ if next_child.type == grammar_token.COMMENT:
index += 1
if index >= num_children - 1:
break
@@ -322,11 +340,11 @@
def _ContainsComments(node):
"""Return True if the list has a comment in it."""
if isinstance(node, pytree.Leaf):
- return pytree_utils.NodeName(node) == 'COMMENT'
- contains_comments = False
+ return node.type == grammar_token.COMMENT
for child in node.children:
- contains_comments = contains_comments or _ContainsComments(child)
- return contains_comments
+ if _ContainsComments(child):
+ return True
+ return False
def _SetMustSplitOnFirstLeaf(node):
@@ -335,7 +353,6 @@
def FindFirstLeaf(node):
if isinstance(node, pytree.Leaf):
return node
-
return FindFirstLeaf(node.children[0])
pytree_utils.SetNodeAnnotation(
diff --git a/yapf/yapflib/pytree_utils.py b/yapf/yapflib/pytree_utils.py
index be8abf5..1244005 100644
--- a/yapf/yapflib/pytree_utils.py
+++ b/yapf/yapflib/pytree_utils.py
@@ -286,10 +286,8 @@
[_PytreeNodeRepr(c) for c in node.children])
if isinstance(node, pytree.Leaf):
return '%s(%s, %r)' % (node.__class__.__name__, NodeName(node), node.value)
- # Throw an exception if it's not an expected type:
- assert isinstance(node, (pytree.Node, pytree.Leaf)), type(node)
def IsCommentStatement(node):
return (NodeName(node) == 'simple_stmt' and
- NodeName(node.children[0]) == 'COMMENT')
+ node.children[0].type == token.COMMENT)
diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py
index 817da2b..2688f0a 100644
--- a/yapf/yapflib/reformatter.py
+++ b/yapf/yapflib/reformatter.py
@@ -48,12 +48,13 @@
"""
final_lines = []
prev_uwline = None # The previous line.
+ indent_width = style.Get('INDENT_WIDTH')
for uwline in _SingleOrMergedLines(uwlines):
first_token = uwline.first
_FormatFirstToken(first_token, uwline.depth, prev_uwline, final_lines)
- indent_amt = style.Get('INDENT_WIDTH') * uwline.depth
+ indent_amt = indent_width * uwline.depth
state = format_decision_state.FormatDecisionState(uwline, indent_amt)
if not uwline.disable:
@@ -79,7 +80,7 @@
while state.next_token:
state.AddTokenToState(newline=False, dry_run=False)
else:
- if not _AnalyzeSolutionSpace(state, dry_run=False):
+ if not _AnalyzeSolutionSpace(state):
# Failsafe mode. If there isn't a solution to the line, then just emit
# it as is.
state = format_decision_state.FormatDecisionState(uwline, indent_amt)
@@ -229,7 +230,7 @@
if (not tok.next_token.whitespace_prefix.startswith('\n') and
not tok.next_token.whitespace_prefix.startswith(' ')):
if (tok.previous_token.value == ':' or
- tok.next_token.value not in ',}])'):
+ tok.next_token.value not in frozenset(',}])')):
formatted_line.append(' ')
formatted_code.append(''.join(formatted_line))
@@ -273,7 +274,7 @@
'state_node'])
-def _AnalyzeSolutionSpace(initial_state, dry_run=False):
+def _AnalyzeSolutionSpace(initial_state):
"""Analyze the entire solution space starting from initial_state.
This implements a variant of Dijkstra's algorithm on the graph that spans
@@ -284,7 +285,6 @@
Arguments:
initial_state: (format_decision_state.FormatDecisionState) The initial state
to start the search from.
- dry_run: (bool) Don't commit changes if True.
Returns:
True if a formatting solution was found. False otherwise.
@@ -313,9 +313,7 @@
if node.state in seen:
continue
- assert penalty >= prev_penalty
prev_penalty = penalty
-
seen.add(node.state)
# FIXME(morbo): Add a 'decision' element?
@@ -327,9 +325,7 @@
# We weren't able to find a solution. Do nothing.
return False
- if not dry_run:
- _ReconstructPath(initial_state, heapq.heappop(p_queue).state_node)
-
+ _ReconstructPath(initial_state, heapq.heappop(p_queue).state_node)
return True
@@ -433,7 +429,7 @@
# The first line in the file. Don't add blank lines.
# FIXME(morbo): Is this correct?
if first_token.newlines is not None:
- pytree_utils.SetNodeAnnotation(first_token.GetPytreeNode(),
+ pytree_utils.SetNodeAnnotation(first_token.node,
pytree_utils.Annotation.NEWLINES, None)
return 0
@@ -444,7 +440,8 @@
prev_last_token = prev_uwline.last
if prev_last_token.is_docstring:
- if not indent_depth and first_token.value in {'class', 'def', 'async'}:
+ if (not indent_depth and
+ first_token.value in frozenset({'class', 'def', 'async'})):
# Separate a class or function from the module-level docstring with two
# blank lines.
return TWO_BLANK_LINES
@@ -454,7 +451,7 @@
else:
return ONE_BLANK_LINE
- if first_token.value in {'class', 'def', '@'}:
+ if first_token.value in frozenset({'class', 'def', '@'}):
# TODO(morbo): This can go once the blank line calculator is more
# sophisticated.
if not indent_depth:
@@ -476,11 +473,11 @@
else:
prev_last_token.AdjustNewlinesBefore(TWO_BLANK_LINES)
if first_token.newlines is not None:
- pytree_utils.SetNodeAnnotation(first_token.GetPytreeNode(),
+ pytree_utils.SetNodeAnnotation(first_token.node,
pytree_utils.Annotation.NEWLINES,
None)
return NO_BLANK_LINES
- elif prev_uwline.first.value in {'class', 'def'}:
+ elif prev_uwline.first.value in frozenset({'class', 'def'}):
if not style.Get('BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'):
pytree_utils.SetNodeAnnotation(first_token.node,
pytree_utils.Annotation.NEWLINES, None)
diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py
index 835ab22..b08d586 100644
--- a/yapf/yapflib/subtype_assigner.py
+++ b/yapf/yapflib/subtype_assigner.py
@@ -66,7 +66,7 @@
if len(node.children) > 1:
index = 0
while index < len(node.children):
- if pytree_utils.NodeName(node.children[index]) != 'COMMENT':
+ if node.children[index].type != token.COMMENT:
break
index += 1
if index < len(node.children):
@@ -313,7 +313,7 @@
def _InsertPseudoParentheses(node):
comment_node = None
if isinstance(node, pytree.Node):
- if pytree_utils.NodeName(node.children[-1]) == 'COMMENT':
+ if node.children[-1].type == token.COMMENT:
comment_node = node.children[-1].clone()
node.children[-1].remove()
diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py
index ae60261..8933023 100644
--- a/yapf/yapflib/unwrapped_line.py
+++ b/yapf/yapflib/unwrapped_line.py
@@ -106,7 +106,6 @@
Arguments:
node: the node to append
"""
- assert isinstance(node, pytree.Leaf)
self.AppendToken(format_token.FormatToken(node))
@property
@@ -190,6 +189,8 @@
def _SpaceRequiredBetween(left, right):
"""Return True if a space is required between the left and right token."""
+ lval = left.value
+ rval = right.value
if (left.is_pseudo_paren and _IsIdNumberStringToken(right) and
left.previous_token and _IsIdNumberStringToken(left.previous_token)):
# Space between keyword... tokens and pseudo parens.
@@ -206,29 +207,29 @@
if _IsIdNumberStringToken(left) and _IsIdNumberStringToken(right):
# Spaces between keyword, string, number, and identifier tokens.
return True
- if left.value == ',' and right.value == ':':
+ if lval == ',' and rval == ':':
# We do want a space between a comma and colon.
return True
- if right.value in ':,':
+ if rval in ':,':
# Otherwise, we never want a space before a colon or comma.
return False
- if left.value == ',' and right.value in ']})':
+ if lval == ',' and rval in ']})':
# Add a space between ending ',' and closing bracket if requested.
return style.Get('SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET')
- if left.value == ',':
+ if lval == ',':
# We want a space after a comma.
return True
- if left.value == 'from' and right.value == '.':
+ if lval == 'from' and rval == '.':
# Space before the '.' in an import statement.
return True
- if left.value == '.' and right.value == 'import':
+ if lval == '.' and rval == 'import':
# Space after the '.' in an import statement.
return True
if ((right.is_keyword or right.is_name) and
(left.is_keyword or left.is_name)):
# Don't merge two keywords/identifiers.
return True
- if left.is_string and right.value not in '[)]}.':
+ if left.is_string and rval not in '[)]}.':
# A string followed by something other than a subscript, closing bracket,
# or dot should have a space after it.
return True
@@ -239,13 +240,13 @@
# No space between two unary operators.
return False
if left.is_binary_op or right.is_binary_op:
- if left.value == '**' or right.value == '**':
+ if lval == '**' or rval == '**':
# Space around the "power" operator.
return style.Get('SPACES_AROUND_POWER_OPERATOR')
# Enforce spaces around binary operators.
return True
- if (_IsUnaryOperator(left) and left.value != 'not' and
- (right.is_name or right.is_number or right.value == '(')):
+ if (_IsUnaryOperator(left) and lval != 'not' and
+ (right.is_name or right.is_number or rval == '(')):
# The previous token was a unary op. No space is desired between it and
# the current token.
return False
@@ -261,55 +262,53 @@
format_token.Subtype.KWARGS_STAR_STAR in left.subtypes):
# Don't add a space after a vararg's star or a keyword's star-star.
return False
- if left.value == '@':
+ if lval == '@':
# Decorators shouldn't be separated from the 'at' sign.
return False
- if left.value == '.' or right.value == '.':
+ if lval == '.' or rval == '.':
# Don't place spaces between dots.
return False
- if ((left.value == '(' and right.value == ')') or
- (left.value == '[' and right.value == ']') or
- (left.value == '{' and right.value == '}')):
+ if ((lval == '(' and rval == ')') or (lval == '[' and rval == ']') or
+ (lval == '{' and rval == '}')):
# Empty objects shouldn't be separted by spaces.
return False
- if (left.value in pytree_utils.OPENING_BRACKETS and
- right.value in pytree_utils.OPENING_BRACKETS):
+ if (lval in pytree_utils.OPENING_BRACKETS and
+ rval in pytree_utils.OPENING_BRACKETS):
# Nested objects' opening brackets shouldn't be separated.
return False
- if (left.value in pytree_utils.CLOSING_BRACKETS and
- right.value in pytree_utils.CLOSING_BRACKETS):
+ if (lval in pytree_utils.CLOSING_BRACKETS and
+ rval in pytree_utils.CLOSING_BRACKETS):
# Nested objects' closing brackets shouldn't be separated.
return False
- if left.value in pytree_utils.CLOSING_BRACKETS and right.value in '([':
+ if lval in pytree_utils.CLOSING_BRACKETS and rval in '([':
# A call, set, dictionary, or subscript that has a call or subscript after
# it shouldn't have a space between them.
return False
- if (left.value in pytree_utils.OPENING_BRACKETS and
- _IsIdNumberStringToken(right)):
+ if lval in pytree_utils.OPENING_BRACKETS and _IsIdNumberStringToken(right):
# Don't separate the opening bracket from the first item.
return False
- if left.is_name and right.value in '([':
+ if left.is_name and rval in '([':
# Don't separate a call or array access from the name.
return False
- if right.value in pytree_utils.CLOSING_BRACKETS:
+ if rval in pytree_utils.CLOSING_BRACKETS:
# Don't separate the closing bracket from the last item.
# FIXME(morbo): This might be too permissive.
return False
- if left.value == 'print' and right.value == '(':
+ if lval == 'print' and rval == '(':
# Special support for the 'print' function.
return False
- if left.value in pytree_utils.OPENING_BRACKETS and _IsUnaryOperator(right):
+ if lval in pytree_utils.OPENING_BRACKETS and _IsUnaryOperator(right):
# Don't separate a unary operator from the opening bracket.
return False
- if (left.value in pytree_utils.OPENING_BRACKETS and
+ if (lval in pytree_utils.OPENING_BRACKETS and
(format_token.Subtype.VARARGS_STAR in right.subtypes or
format_token.Subtype.KWARGS_STAR_STAR in right.subtypes)):
# Don't separate a '*' or '**' from the opening bracket.
return False
- if right.value == ';':
+ if rval == ';':
# Avoid spaces before a semicolon. (Why is there a semicolon?!)
return False
- if left.value == '(' and right.value == 'await':
+ if lval == '(' and rval == 'await':
# Special support for the 'await' keyword. Don't separate the 'await'
# keyword from an opening paren.
return False
@@ -321,8 +320,8 @@
if prev_token.is_comment:
# Must break if the previous token was a comment.
return True
- if (IsSurroundedByBrackets(cur_token) and cur_token.is_string and
- prev_token.is_string):
+ if (cur_token.is_string and prev_token.is_string and
+ IsSurroundedByBrackets(cur_token)):
# We want consecutive strings to be on separate lines. This is a
# reasonable assumption, because otherwise they should have written them
# all on the same line, or with a '+'.
@@ -334,32 +333,33 @@
def _CanBreakBefore(prev_token, cur_token):
"""Return True if a line break may occur before the current token."""
+ pval = prev_token.value
+ cval = cur_token.value
if py3compat.PY3:
- if prev_token.value == 'yield' and cur_token.value == 'from':
+ if pval == 'yield' and cval == 'from':
# Don't break before a yield argument.
return False
- if (prev_token.value in {'async', 'await'} and
- cur_token.value in {'def', 'with', 'for'}):
+ if pval in {'async', 'await'} and cval in {'def', 'with', 'for'}:
# Don't break after sync keywords.
return False
if cur_token.split_penalty >= split_penalty.UNBREAKABLE:
return False
- if prev_token.value == '@':
+ if pval == '@':
# Don't break right after the beginning of a decorator.
return False
- if cur_token.value == ':':
+ if cval == ':':
# Don't break before the start of a block of code.
return False
- if cur_token.value == ',':
+ if cval == ',':
# Don't break before a comma.
return False
- if prev_token.is_name and cur_token.value == '(':
+ if prev_token.is_name and cval == '(':
# Don't break in the middle of a function definition or call.
return False
- if prev_token.is_name and cur_token.value == '[':
+ if prev_token.is_name and cval == '[':
# Don't break in the middle of an array dereference.
return False
- if prev_token.is_name and cur_token.value == '.':
+ if prev_token.is_name and cval == '.':
# Don't break before the '.' in a dotted name.
return False
if cur_token.is_comment and prev_token.lineno == cur_token.lineno:
@@ -409,7 +409,9 @@
def _SplitPenalty(prev_token, cur_token):
"""Return the penalty for breaking the line before the current token."""
- if prev_token.value == 'not':
+ pval = prev_token.value
+ cval = cur_token.value
+ if pval == 'not':
return split_penalty.UNBREAKABLE
if cur_token.node_split_penalty > 0:
@@ -417,28 +419,28 @@
if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'):
# Prefer to split before 'and' and 'or'.
- if prev_token.value in _LOGICAL_OPERATORS:
+ if pval in _LOGICAL_OPERATORS:
return style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR')
- if cur_token.value in _LOGICAL_OPERATORS:
+ if cval in _LOGICAL_OPERATORS:
return 0
else:
# Prefer to split after 'and' and 'or'.
- if prev_token.value in _LOGICAL_OPERATORS:
+ if pval in _LOGICAL_OPERATORS:
return 0
- if cur_token.value in _LOGICAL_OPERATORS:
+ if cval in _LOGICAL_OPERATORS:
return style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR')
if style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'):
# Prefer to split before '&', '|', and '^'.
- if prev_token.value in _BITWISE_OPERATORS:
+ if pval in _BITWISE_OPERATORS:
return style.Get('SPLIT_PENALTY_BITWISE_OPERATOR')
- if cur_token.value in _BITWISE_OPERATORS:
+ if cval in _BITWISE_OPERATORS:
return 0
else:
# Prefer to split after '&', '|', and '^'.
- if prev_token.value in _BITWISE_OPERATORS:
+ if pval in _BITWISE_OPERATORS:
return 0
- if cur_token.value in _BITWISE_OPERATORS:
+ if cval in _BITWISE_OPERATORS:
return style.Get('SPLIT_PENALTY_BITWISE_OPERATOR')
if (format_token.Subtype.COMP_FOR in cur_token.subtypes or
@@ -448,7 +450,7 @@
if format_token.Subtype.UNARY_OPERATOR in prev_token.subtypes:
# Try not to break after a unary operator.
return style.Get('SPLIT_PENALTY_AFTER_UNARY_OPERATOR')
- if prev_token.value == ',':
+ if pval == ',':
# Breaking after a comma is fine, if need be.
return 0
if prev_token.is_binary_op:
@@ -458,25 +460,25 @@
format_token.Subtype.KWARGS_STAR_STAR in prev_token.subtypes):
# Don't split after a varargs * or kwargs **.
return split_penalty.UNBREAKABLE
- if prev_token.OpensScope() and cur_token.value != '(':
+ if prev_token.OpensScope() and cval != '(':
# Slightly prefer
return style.Get('SPLIT_PENALTY_AFTER_OPENING_BRACKET')
- if cur_token.value == ':':
+ if cval == ':':
# Don't split before a colon.
return split_penalty.UNBREAKABLE
- if cur_token.value == '=':
+ if cval == '=':
# Don't split before an assignment.
return split_penalty.UNBREAKABLE
if (format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in prev_token.subtypes or
format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in cur_token.subtypes):
# Don't break before or after an default or named assignment.
return split_penalty.UNBREAKABLE
- if cur_token.value == '==':
+ if cval == '==':
# We would rather not split before an equality operator.
return split_penalty.STRONGLY_CONNECTED
if cur_token.ClosesScope():
# Give a slight penalty for splitting before the closing scope.
return 100
- if prev_token.value in _TERM_OPERATORS or cur_token.value in _TERM_OPERATORS:
+ if pval in _TERM_OPERATORS or cval in _TERM_OPERATORS:
return 50
return 0