]> git.madduck.net Git - etc/vim.git/commitdiff

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Automatic management of parentheses in assignments
authorŁukasz Langa <lukasz@langa.pl>
Wed, 9 May 2018 00:28:40 +0000 (17:28 -0700)
committerŁukasz Langa <lukasz@langa.pl>
Wed, 9 May 2018 04:57:09 +0000 (21:57 -0700)
Fixes #140

Note: this is an evolution but the end result needs to be different.  See
cantfit.py for some good examples on bad formatting caused by this change.

README.md
black.py
tests/cantfit.py
tests/expression.diff
tests/expression.py

index cb92f57b8305803e639096db58e65a5ab58216d5..aca49994cd7f268ad520d41384ed0801f083763e 100644 (file)
--- a/README.md
+++ b/README.md
@@ -327,6 +327,11 @@ interesting cases:
 - `for (...) in (...):`
 - `assert (...), (...)`
 - `from X import (...)`
+- assignments like:
+  - `target = (...)`
+  - `target: type = (...)`
+  - `some, *un, packing = (...)`
+  - `augmented += (...)`
 
 In those cases, parentheses are removed when the entire statement fits
 in one line, or if the inner expression doesn't have any delimiters to
@@ -540,6 +545,9 @@ More details can be found in [CONTRIBUTING](CONTRIBUTING.md).
 
 * slices are now formatted according to PEP 8 (#178)
 
+* parentheses are now also managed automatically on the right-hand side
+  of assignments and return statements (#140)
+
 * math operators now use their respective priorities for delimiting multiline
   expressions (#148)
 
index eb99a41b04217f3cdc0cc551be97014eee7fe62f..00d5758dd802e9a3a110c0380d32c3f287c1ce44 100644 (file)
--- a/black.py
+++ b/black.py
@@ -599,6 +599,22 @@ TEST_DESCENDANTS = {
     syms.term,
     syms.power,
 }
+ASSIGNMENTS = {
+    "=",
+    "+=",
+    "-=",
+    "*=",
+    "@=",
+    "/=",
+    "%=",
+    "&=",
+    "|=",
+    "^=",
+    "<<=",
+    ">>=",
+    "**=",
+    "//=",
+}
 COMPREHENSION_PRIORITY = 20
 COMMA_PRIORITY = 18
 TERNARY_PRIORITY = 16
@@ -994,8 +1010,9 @@ class Line:
             and subscript_start.type == syms.subscriptlist
         ):
             subscript_start = child_towards(subscript_start, leaf)
-        return subscript_start is not None and any(
-            n.type in TEST_DESCENDANTS for n in subscript_start.pre_order()
+        return (
+            subscript_start is not None
+            and any(n.type in TEST_DESCENDANTS for n in subscript_start.pre_order())
         )
 
     def __str__(self) -> str:
@@ -1252,7 +1269,7 @@ class LineGenerator(Visitor[Line]):
         """Visit a statement.
 
         This implementation is shared for `if`, `while`, `for`, `try`, `except`,
-        `def`, `with`, `class`, and `assert`.
+        `def`, `with`, `class`, `assert` and assignments.
 
         The relevant Python language `keywords` for a given statement will be
         NAME leaves within it. This methods puts those on a separate line.
@@ -1368,6 +1385,8 @@ class LineGenerator(Visitor[Line]):
         self.visit_with_stmt = partial(v, keywords={"with"}, parens=Ø)
         self.visit_funcdef = partial(v, keywords={"def"}, parens=Ø)
         self.visit_classdef = partial(v, keywords={"class"}, parens=Ø)
+        self.visit_expr_stmt = partial(v, keywords=Ø, parens=ASSIGNMENTS)
+        self.visit_return_stmt = partial(v, keywords={"return"}, parens={"return"})
         self.visit_async_funcdef = self.visit_async_stmt
         self.visit_decorated = self.visit_decorators
 
index 99bcaa04ae0d7ad2663188519260965e08b09a8e..54f692c8b57158768e4561a4098cae020b3eafbe 100644 (file)
@@ -25,3 +25,43 @@ normal_name = normal_function_name(
     "eggs with spam and eggs and spam with eggs with spam and eggs and spam with eggs with spam and eggs and spam with eggs",
     this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it=0,
 )
+
+
+# output
+
+
+# long variable name
+this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = (
+    0
+)
+this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = (
+    1
+)  # with a comment
+this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = [
+    1, 2, 3
+]
+this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = (
+    function()
+)
+this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function(
+    arg1, arg2, arg3
+)
+this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function(
+    [1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3
+)
+# long function name
+normal_name = (
+    but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying()
+)
+normal_name = but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying(
+    arg1, arg2, arg3
+)
+normal_name = but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying(
+    [1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3
+)
+# long arguments
+normal_name = normal_function_name(
+    "but with super long string arguments that on their own exceed the line limit so there's no way it can ever fit",
+    "eggs with spam and eggs and spam with eggs with spam and eggs and spam with eggs with spam and eggs and spam with eggs",
+    this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it=0,
+)
index 7004a3eda93d8030ae69f5a181f8601c61790996..2af955c88acc125913682f96574d09f308b357db 100644 (file)
 -foo = (lambda port_id, ignore_missing: {"port1": port1_resource, "port2": port2_resource}[port_id])
 +lambda a, b, c=True, *, d=(1 << v2), e="str": a
 +lambda a, b, c=True, *vararg, d=(v1 << 2), e="str", **kwargs: a + b
-+foo = (
-+    lambda port_id, ignore_missing: {"port1": port1_resource, "port2": port2_resource}[
-+        port_id
-+    ]
-+)
++foo = lambda port_id, ignore_missing: {
++    "port1": port1_resource, "port2": port2_resource
++}[
++    port_id
++]
  1 if True else 2
  str or None if True else str or bytes or None
  (str or None) if True else (str or bytes or None)
 +    **kwargs,
 +}
  a = (1,)
- b = 1,
+-b = 1,
++b = (1,)
  c = 1
  d = (1,) + a + (2,)
  e = (1,).count(1)
 -what_is_up_with_those_new_coord_names = (coord_names + set(vars_to_create)) + set(vars_to_remove)
 -what_is_up_with_those_new_coord_names = (coord_names | set(vars_to_create)) - set(vars_to_remove)
 -result = session.query(models.Customer.id).filter(models.Customer.account_id == account_id, models.Customer.email == email_address).order_by(models.Customer.id.asc(),).all()
-+what_is_up_with_those_new_coord_names = (coord_names + set(vars_to_create)) + set(
-+    vars_to_remove
++what_is_up_with_those_new_coord_names = (
++    (coord_names + set(vars_to_create)) + set(vars_to_remove)
 +)
-+what_is_up_with_those_new_coord_names = (coord_names | set(vars_to_create)) - set(
-+    vars_to_remove
++what_is_up_with_those_new_coord_names = (
++    (coord_names | set(vars_to_create)) - set(vars_to_remove)
 +)
 +result = session.query(models.Customer.id).filter(
 +    models.Customer.account_id == account_id, models.Customer.email == email_address
 +
  def gen():
      yield from outside_of_generator
-     a = (yield)
+-    a = (yield)
++    a = yield
 +
  async def f():
      await some.complicated[0].call(with_args=(True or (1 is not 1)))
 -print(* [] or [1])
index d3451c5c8bfc3303b7bd73a78e4e772c74b5a82c..82d9dfa719d9c9ac6ccc34b78547ec09cd13689a 100644 (file)
@@ -266,11 +266,11 @@ lambda a=True: a
 lambda a, b, c=True: a
 lambda a, b, c=True, *, d=(1 << v2), e="str": a
 lambda a, b, c=True, *vararg, d=(v1 << 2), e="str", **kwargs: a + b
-foo = (
-    lambda port_id, ignore_missing: {"port1": port1_resource, "port2": port2_resource}[
-        port_id
-    ]
-)
+foo = lambda port_id, ignore_missing: {
+    "port1": port1_resource, "port2": port2_resource
+}[
+    port_id
+]
 1 if True else 2
 str or None if True else str or bytes or None
 (str or None) if True else (str or bytes or None)
@@ -397,15 +397,15 @@ SomeName
     **kwargs,
 }
 a = (1,)
-b = 1,
+b = (1,)
 c = 1
 d = (1,) + a + (2,)
 e = (1,).count(1)
-what_is_up_with_those_new_coord_names = (coord_names + set(vars_to_create)) + set(
-    vars_to_remove
+what_is_up_with_those_new_coord_names = (
+    (coord_names + set(vars_to_create)) + set(vars_to_remove)
 )
-what_is_up_with_those_new_coord_names = (coord_names | set(vars_to_create)) - set(
-    vars_to_remove
+what_is_up_with_those_new_coord_names = (
+    (coord_names | set(vars_to_create)) - set(vars_to_remove)
 )
 result = session.query(models.Customer.id).filter(
     models.Customer.account_id == account_id, models.Customer.email == email_address
@@ -424,7 +424,7 @@ mapping = {
 
 def gen():
     yield from outside_of_generator
-    a = (yield)
+    a = yield
 
 
 async def f():