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.
This commit is contained in:
Łukasz Langa 2018-05-08 15:44:44 -07:00
parent e196180a0d
commit 1747c388bb
5 changed files with 55 additions and 2 deletions

View File

@ -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

View File

@ -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

View File

@ -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,
)

18
tests/function2.py Normal file
View File

@ -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,
)

View File

@ -167,6 +167,14 @@ def test_function(self) -> None:
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")