From: Ɓukasz Langa Date: Tue, 8 May 2018 22:44:44 +0000 (-0700) Subject: Discover whether a file is Python 3.6+ also by stars in calls X-Git-Url: https://git.madduck.net/etc/vim.git/commitdiff_plain/1747c388bba0c87f75a6239d56e3b51f7455e93d?ds=inline Discover whether a file is Python 3.6+ also by stars in calls Fixes a pathological situation where if a function signature used a trailing comma but was later reformatted to a single line (with the trailing comma removed), Black would change its mind whether a file is Python 3.6-compatible between runs. --- diff --git a/README.md b/README.md index a9ec9ea..8c5bbd2 100644 --- a/README.md +++ b/README.md @@ -549,6 +549,11 @@ More details can be found in [CONTRIBUTING](CONTRIBUTING.md). * fixed not splitting long from-imports with only a single name +* fixed Python 3.6+ file discovery by also looking at function calls with + unpacking. This fixed non-deterministic formatting if trailing commas + where used both in function signatures with stars and function calls + with stars but the former would be reformatted to a single line. + ### 18.4a4 diff --git a/black.py b/black.py index d2d23c8..151dc8c 100644 --- a/black.py +++ b/black.py @@ -2337,7 +2337,7 @@ def is_python36(node: Node) -> bool: Currently looking for: - f-strings; and - - trailing commas after * or ** in function signatures. + - trailing commas after * or ** in function signatures and calls. """ for n in node.pre_order(): if n.type == token.STRING: @@ -2346,7 +2346,7 @@ def is_python36(node: Node) -> bool: return True elif ( - n.type == syms.typedargslist + n.type in {syms.typedargslist, syms.arglist} and n.children and n.children[-1].type == token.COMMA ): @@ -2354,6 +2354,11 @@ def is_python36(node: Node) -> bool: if ch.type in STARS: return True + if ch.type == syms.argument: + for argch in ch.children: + if argch.type in STARS: + return True + return False diff --git a/tests/function.py b/tests/function.py index 4ec9057..a181212 100644 --- a/tests/function.py +++ b/tests/function.py @@ -81,6 +81,15 @@ def trailing_comma(): C: 0.1 * (10.0 / 12), D: 0.1 * (10.0 / 12), } +def f( + a, + **kwargs, +) -> A: + return A( + very_long_argument_name1=very_long_value_for_the_argument, + very_long_argument_name2=very_long_value_for_the_argument, + **kwargs, + ) # output @@ -212,3 +221,11 @@ def trailing_comma(): C: 0.1 * (10.0 / 12), D: 0.1 * (10.0 / 12), } + + +def f(a, **kwargs) -> A: + return A( + very_long_argument_name1=very_long_value_for_the_argument, + very_long_argument_name2=very_long_value_for_the_argument, + **kwargs, + ) diff --git a/tests/function2.py b/tests/function2.py new file mode 100644 index 0000000..1b9d7b6 --- /dev/null +++ b/tests/function2.py @@ -0,0 +1,18 @@ +def f( + a, + **kwargs, +) -> A: + return A( + very_long_argument_name1=very_long_value_for_the_argument, + very_long_argument_name2=very_long_value_for_the_argument, + **kwargs, + ) + +# output + +def f(a, **kwargs) -> A: + return A( + very_long_argument_name1=very_long_value_for_the_argument, + very_long_argument_name2=very_long_value_for_the_argument, + **kwargs, + ) diff --git a/tests/test_black.py b/tests/test_black.py index 951b298..5b84c3c 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -167,6 +167,14 @@ class BlackTestCase(unittest.TestCase): black.assert_equivalent(source, actual) black.assert_stable(source, actual, line_length=ll) + @patch("black.dump_to_file", dump_to_stderr) + def test_function2(self) -> None: + source, expected = read_data("function2") + actual = fs(source) + self.assertFormatEqual(expected, actual) + black.assert_equivalent(source, actual) + black.assert_stable(source, actual, line_length=ll) + @patch("black.dump_to_file", dump_to_stderr) def test_expression(self) -> None: source, expected = read_data("expression")