Split before function call in list
If the whole list cannot fit on a single line, then split before a function
call. This prevents things like this:
def foo():
return [
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')
]
diff --git a/CHANGELOG b/CHANGELOG
index 5507ba0..4db4add 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -10,6 +10,8 @@
- Increase penalty for excess characters.
- Check that we have enough children before trying to access them all.
- Remove trailing whitespaces from comments.
+- Split before a function call in a list if the full list isn't able to fit on
+ a single line.
## [0.16.1] 2017-03-22
### Changed
diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py
index 3281940..b5b0409 100644
--- a/yapf/yapflib/format_decision_state.py
+++ b/yapf/yapflib/format_decision_state.py
@@ -189,6 +189,38 @@
# 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
diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py
index a396a05..de270cf 100644
--- a/yapf/yapflib/format_token.py
+++ b/yapf/yapflib/format_token.py
@@ -121,8 +121,8 @@
"""
indent_char = '\t' if style.Get('USE_TABS') else ' '
token_indent_char = indent_char if newlines_before > 0 else ' '
- indent_before = (
- indent_char * indent_level * style.Get('INDENT_WIDTH') + token_indent_char * spaces)
+ indent_before = (indent_char * indent_level * style.Get('INDENT_WIDTH') +
+ token_indent_char * spaces)
if self.is_comment:
comment_lines = [s.lstrip() for s in self.value.splitlines()]
diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py
index 77b2f1e..3b3210d 100644
--- a/yapf/yapflib/unwrapped_line.py
+++ b/yapf/yapflib/unwrapped_line.py
@@ -397,19 +397,19 @@
if previous_token.value == '(':
if paren_count == 0:
- return True
+ return previous_token
paren_count += 1
elif previous_token.value == '{':
if brace_count == 0:
- return True
+ return previous_token
brace_count += 1
elif previous_token.value == '[':
if sq_bracket_count == 0:
- return True
+ return previous_token
sq_bracket_count += 1
previous_token = previous_token.previous_token
- return False
+ return None
_LOGICAL_OPERATORS = frozenset({'and', 'or'})
diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py
index f06d44d..fe5d21e 100644
--- a/yapftests/reformatter_basic_test.py
+++ b/yapftests/reformatter_basic_test.py
@@ -2147,6 +2147,33 @@
uwlines = yapf_test_helper.ParseAndUnwrap(code)
self.assertCodeEqual(code, reformatter.Reformat(uwlines))
+ def testListWithFunctionCalls(self):
+ unformatted_code = textwrap.dedent("""\
+ def foo():
+ return [
+ 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')
+ ]
+ """)
+ expected_code = textwrap.dedent("""\
+ def foo():
+ return [
+ 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')
+ ]
+ """)
+ uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code)
+ self.assertEqual(expected_code, reformatter.Reformat(uwlines))
+
if __name__ == '__main__':
unittest.main()
diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py
index 1bdac25..8eed74b 100644
--- a/yapftests/reformatter_buganizer_test.py
+++ b/yapftests/reformatter_buganizer_test.py
@@ -28,6 +28,45 @@
def setUpClass(cls):
style.SetGlobalStyle(style.CreateChromiumStyle())
+ def testB36806207(self):
+ unformatted_code = textwrap.dedent("""\
+ def _():
+ linearity_data = [[row] for row in [
+ "%.1f mm" % (np.mean(linearity_values["pos_error"]) * 1000.0),
+ "%.1f mm" % (np.max(linearity_values["pos_error"]) * 1000.0),
+ "%.1f mm" % (np.mean(linearity_values["pos_error_chunk_mean"]) * 1000.0),
+ "%.1f mm" % (np.max(linearity_values["pos_error_chunk_max"]) * 1000.0),
+ "%.1f deg" % math.degrees(np.mean(linearity_values["rot_noise"])),
+ "%.1f deg" % math.degrees(np.max(linearity_values["rot_noise"])),
+ "%.1f deg" % math.degrees(np.mean(linearity_values["rot_drift"])),
+ "%.1f deg" % math.degrees(np.max(linearity_values["rot_drift"])),
+ "%.1f%%" % (np.max(linearity_values["pos_discontinuity"]) * 100.0),
+ "%.1f%%" % (np.max(linearity_values["rot_discontinuity"]) * 100.0)
+ ]]
+ """)
+ expected_code = textwrap.dedent("""\
+ def _():
+ linearity_data = [
+ [row]
+ for row in [
+ "%.1f mm" % (np.mean(linearity_values["pos_error"]) * 1000.0),
+ "%.1f mm" % (np.max(linearity_values["pos_error"]) * 1000.0),
+ "%.1f mm" % (
+ np.mean(linearity_values["pos_error_chunk_mean"]) * 1000.0),
+ "%.1f mm" % (
+ np.max(linearity_values["pos_error_chunk_max"]) * 1000.0),
+ "%.1f deg" % math.degrees(np.mean(linearity_values["rot_noise"])),
+ "%.1f deg" % math.degrees(np.max(linearity_values["rot_noise"])),
+ "%.1f deg" % math.degrees(np.mean(linearity_values["rot_drift"])),
+ "%.1f deg" % math.degrees(np.max(linearity_values["rot_drift"])),
+ "%.1f%%" % (np.max(linearity_values["pos_discontinuity"]) * 100.0),
+ "%.1f%%" % (np.max(linearity_values["rot_discontinuity"]) * 100.0)
+ ]
+ ]
+ """)
+ uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code)
+ self.assertEqual(expected_code, reformatter.Reformat(uwlines))
+
def testB36215507(self):
code = textwrap.dedent("""\
class X():