"""
from functools import partial, wraps
import sys
-from typing import Collection, Iterator, List, Optional, Set, Union
+from typing import Collection, Iterator, List, Optional, Set, Union, cast
from black.nodes import WHITESPACE, RARROW, STATEMENT, STANDALONE_COMMENT
from black.nodes import ASSIGNMENTS, OPENING_BRACKETS, CLOSING_BRACKETS
):
wrap_in_parentheses(node, leaf)
+ if Preview.remove_redundant_parens in self.mode:
+ remove_await_parens(node)
+
yield from self.visit_default(node)
def visit_SEMI(self, leaf: Leaf) -> Iterator[Line]:
)
+def remove_await_parens(node: Node) -> None:
+ if node.children[0].type == token.AWAIT and len(node.children) > 1:
+ if (
+ node.children[1].type == syms.atom
+ and node.children[1].children[0].type == token.LPAR
+ ):
+ if maybe_make_parens_invisible_in_atom(
+ node.children[1],
+ parent=node,
+ remove_brackets_around_comma=True,
+ ):
+ wrap_in_parentheses(node, node.children[1], visible=False)
+
+ # Since await is an expression we shouldn't remove
+ # brackets in cases where this would change
+ # the AST due to operator precedence.
+ # Therefore we only aim to remove brackets around
+ # power nodes that aren't also await expressions themselves.
+ # https://peps.python.org/pep-0492/#updated-operator-precedence-table
+ # N.B. We've still removed any redundant nested brackets though :)
+ opening_bracket = cast(Leaf, node.children[1].children[0])
+ closing_bracket = cast(Leaf, node.children[1].children[-1])
+ bracket_contents = cast(Node, node.children[1].children[1])
+ if bracket_contents.type != syms.power:
+ ensure_visible(opening_bracket)
+ ensure_visible(closing_bracket)
+ elif (
+ bracket_contents.type == syms.power
+ and bracket_contents.children[0].type == token.AWAIT
+ ):
+ ensure_visible(opening_bracket)
+ ensure_visible(closing_bracket)
+ # If we are in a nested await then recurse down.
+ remove_await_parens(bracket_contents)
+
+
def remove_with_parens(node: Node, parent: Node) -> None:
"""Recursively hide optional parens in `with` statements."""
# Removing all unnecessary parentheses in with statements in one pass is a tad
--- /dev/null
+import asyncio
+
+# Control example
+async def main():
+ await asyncio.sleep(1)
+
+# Remove brackets for short coroutine/task
+async def main():
+ await (asyncio.sleep(1))
+
+async def main():
+ await (
+ asyncio.sleep(1)
+ )
+
+async def main():
+ await (asyncio.sleep(1)
+ )
+
+# Check comments
+async def main():
+ await ( # Hello
+ asyncio.sleep(1)
+ )
+
+async def main():
+ await (
+ asyncio.sleep(1) # Hello
+ )
+
+async def main():
+ await (
+ asyncio.sleep(1)
+ ) # Hello
+
+# Long lines
+async def main():
+ await asyncio.gather(asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1))
+
+# Same as above but with magic trailing comma in function
+async def main():
+ await asyncio.gather(asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1),)
+
+# Cr@zY Br@ck3Tz
+async def main():
+ await (
+ (((((((((((((
+ ((( (((
+ ((( (((
+ ((( (((
+ ((( (((
+ ((black(1)))
+ ))) )))
+ ))) )))
+ ))) )))
+ ))) )))
+ )))))))))))))
+ )
+
+# Keep brackets around non power operations and nested awaits
+async def main():
+ await (set_of_tasks | other_set)
+
+async def main():
+ await (await asyncio.sleep(1))
+
+# It's awaits all the way down...
+async def main():
+ await (await x)
+
+async def main():
+ await (yield x)
+
+async def main():
+ await (await (asyncio.sleep(1)))
+
+async def main():
+ await (await (await (await (await (asyncio.sleep(1))))))
+
+# output
+import asyncio
+
+# Control example
+async def main():
+ await asyncio.sleep(1)
+
+
+# Remove brackets for short coroutine/task
+async def main():
+ await asyncio.sleep(1)
+
+
+async def main():
+ await asyncio.sleep(1)
+
+
+async def main():
+ await asyncio.sleep(1)
+
+
+# Check comments
+async def main():
+ await asyncio.sleep(1) # Hello
+
+
+async def main():
+ await asyncio.sleep(1) # Hello
+
+
+async def main():
+ await asyncio.sleep(1) # Hello
+
+
+# Long lines
+async def main():
+ await asyncio.gather(
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ )
+
+
+# Same as above but with magic trailing comma in function
+async def main():
+ await asyncio.gather(
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ )
+
+
+# Cr@zY Br@ck3Tz
+async def main():
+ await black(1)
+
+
+# Keep brackets around non power operations and nested awaits
+async def main():
+ await (set_of_tasks | other_set)
+
+
+async def main():
+ await (await asyncio.sleep(1))
+
+
+# It's awaits all the way down...
+async def main():
+ await (await x)
+
+
+async def main():
+ await (yield x)
+
+
+async def main():
+ await (await asyncio.sleep(1))
+
+
+async def main():
+ await (await (await (await (await asyncio.sleep(1)))))