Repository: google/yapf

Issue:
How to prevent YAPF from joining lines in dictionaries and lists?
YAPF converts
```
DJANGO_TEMPLATES_OPTIONS = {
  "context_processors": []
}
```
to
```
DJANGO_TEMPLATES_OPTIONS = {"context_processors": []}
```
and I cannot find the option to disable such behavior.

Is it possible?

Comments:

Patch:
diff --git a/CHANGELOG b/CHANGELOG
index d7a465c..b05a6f4 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -13,6 +13,7 @@
 - Corrected how `DEDENT_CLOSING_BRACKETS` and `COALESCE_BRACKETS` interacted.
 - Fix return value to return a boolean.
 - Correct vim plugin not to clobber edited code if yapf returns an error.
+- Ensured comma-terminated tuples with multiple elements are split onto separate lines.
 
 ## [0.16.3] 2017-07-13
 ### Changed
diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py
index c67c1c6..8dbbfe0 100644
--- a/yapf/yapflib/pytree_unwrapper.py
+++ b/yapf/yapflib/pytree_unwrapper.py
@@ -258,8 +258,7 @@ class PyTreeUnwrapper(pytree_visitor.PyTreeVisitor):
     self.DefaultNodeVisit(node)
 
   def Visit_testlist_gexp(self, node):  # pylint: disable=invalid-name
-    if _ContainsComments(node):
-      _DetermineMustSplitAnnotation(node)
+    _DetermineMustSplitAnnotation(node)
     self.DefaultNodeVisit(node)
 
   def Visit_arglist(self, node):  # pylint: disable=invalid-name
@@ -336,6 +335,11 @@ def _AdjustSplitPenalty(uwline):
 def _DetermineMustSplitAnnotation(node):
   """Enforce a split in the list if the list ends with a comma."""
   if not _ContainsComments(node):
+    token = next(node.parent.leaves())
+    if token.value == '(':
+      if sum(1 for ch in node.children
+             if pytree_utils.NodeName(ch) == 'COMMA') < 2:
+        return
     if (not isinstance(node.children[-1], pytree.Leaf) or
         node.children[-1].value != ','):
       return


Test patch:
diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py
index 0ce8da8..c205f47 100644
--- a/yapftests/reformatter_basic_test.py
+++ b/yapftests/reformatter_basic_test.py
@@ -459,10 +459,17 @@ class BasicReformatterTest(yapf_test_helper.YAPFTest):
 
   def testOpeningAndClosingBrackets(self):
     unformatted_code = textwrap.dedent("""\
+        foo( (1, ) )
+        foo( ( 1, 2, 3  ) )
         foo( ( 1, 2, 3, ) )
         """)
     expected_formatted_code = textwrap.dedent("""\
-        foo((1, 2, 3,))
+        foo((1,))
+        foo((1, 2, 3))
+        foo((
+            1,
+            2,
+            3,))
         """)
     uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code)
     self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines))
diff --git a/yapftests/reformatter_facebook_test.py b/yapftests/reformatter_facebook_test.py
index 4706786..953d290 100644
--- a/yapftests/reformatter_facebook_test.py
+++ b/yapftests/reformatter_facebook_test.py
@@ -107,7 +107,7 @@ v, w, x, y, z
     self.assertCodeEqual(code, reformatter.Reformat(uwlines))
 
   def testDedentTestListGexp(self):
-    code = textwrap.dedent("""\
+    unformatted_code = textwrap.dedent("""\
         try:
             pass
         except (
@@ -122,8 +122,27 @@ v, w, x, y, z
         ) as exception:
             pass
         """)
-    uwlines = yapf_test_helper.ParseAndUnwrap(code)
-    self.assertCodeEqual(code, reformatter.Reformat(uwlines))
+    expected_formatted_code = textwrap.dedent("""\
+        try:
+            pass
+        except (
+            IOError, OSError, LookupError, RuntimeError, OverflowError
+        ) as exception:
+            pass
+
+        try:
+            pass
+        except (
+            IOError,
+            OSError,
+            LookupError,
+            RuntimeError,
+            OverflowError,
+        ) as exception:
+            pass
+        """)
+    uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code)
+    self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines))
 
   def testBrokenIdempotency(self):
     # TODO(ambv): The following behaviour should be fixed.