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:
parent
e196180a0d
commit
1747c388bb
@ -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 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
|
### 18.4a4
|
||||||
|
|
||||||
|
9
black.py
9
black.py
@ -2337,7 +2337,7 @@ def is_python36(node: Node) -> bool:
|
|||||||
|
|
||||||
Currently looking for:
|
Currently looking for:
|
||||||
- f-strings; and
|
- 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():
|
for n in node.pre_order():
|
||||||
if n.type == token.STRING:
|
if n.type == token.STRING:
|
||||||
@ -2346,7 +2346,7 @@ def is_python36(node: Node) -> bool:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
elif (
|
elif (
|
||||||
n.type == syms.typedargslist
|
n.type in {syms.typedargslist, syms.arglist}
|
||||||
and n.children
|
and n.children
|
||||||
and n.children[-1].type == token.COMMA
|
and n.children[-1].type == token.COMMA
|
||||||
):
|
):
|
||||||
@ -2354,6 +2354,11 @@ def is_python36(node: Node) -> bool:
|
|||||||
if ch.type in STARS:
|
if ch.type in STARS:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
if ch.type == syms.argument:
|
||||||
|
for argch in ch.children:
|
||||||
|
if argch.type in STARS:
|
||||||
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,6 +81,15 @@ def trailing_comma():
|
|||||||
C: 0.1 * (10.0 / 12),
|
C: 0.1 * (10.0 / 12),
|
||||||
D: 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
|
# output
|
||||||
|
|
||||||
@ -212,3 +221,11 @@ def trailing_comma():
|
|||||||
C: 0.1 * (10.0 / 12),
|
C: 0.1 * (10.0 / 12),
|
||||||
D: 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
18
tests/function2.py
Normal 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,
|
||||||
|
)
|
@ -167,6 +167,14 @@ def test_function(self) -> None:
|
|||||||
black.assert_equivalent(source, actual)
|
black.assert_equivalent(source, actual)
|
||||||
black.assert_stable(source, actual, line_length=ll)
|
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)
|
@patch("black.dump_to_file", dump_to_stderr)
|
||||||
def test_expression(self) -> None:
|
def test_expression(self) -> None:
|
||||||
source, expected = read_data("expression")
|
source, expected = read_data("expression")
|
||||||
|
Loading…
Reference in New Issue
Block a user