Do not wrap implicitly concatenated strings used as func args in parens (#3640)

This commit is contained in:
Yilei "Dolee" Yang 2023-04-28 11:10:01 -07:00 committed by GitHub
parent de65741b8d
commit e712e48e06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 113 additions and 167 deletions

View File

@ -14,6 +14,9 @@
<!-- Changes that affect Black's preview style --> <!-- Changes that affect Black's preview style -->
- Implicitly concatenated strings used as function args are no longer wrapped inside
parentheses (#3640)
### Configuration ### Configuration
<!-- Changes to how Black can be configured --> <!-- Changes to how Black can be configured -->

View File

@ -503,10 +503,8 @@ def main( # noqa: C901
user_level_config = str(find_user_pyproject_toml()) user_level_config = str(find_user_pyproject_toml())
if config == user_level_config: if config == user_level_config:
out( out(
( "Using configuration from user-level config at "
"Using configuration from user-level config at " f"'{user_level_config}'.",
f"'{user_level_config}'."
),
fg="blue", fg="blue",
) )
elif config_source in ( elif config_source in (

View File

@ -188,10 +188,8 @@ class Mode:
def __post_init__(self) -> None: def __post_init__(self) -> None:
if self.experimental_string_processing: if self.experimental_string_processing:
warn( warn(
( "`experimental string processing` has been included in `preview`"
"`experimental string processing` has been included in `preview`" " and deprecated. Use `preview` instead.",
" and deprecated. Use `preview` instead."
),
Deprecated, Deprecated,
) )

View File

@ -29,11 +29,9 @@
except ImportError: except ImportError:
if sys.version_info < (3, 8) and not _IS_PYPY: if sys.version_info < (3, 8) and not _IS_PYPY:
print( print(
( "The typed_ast package is required but not installed.\n"
"The typed_ast package is required but not installed.\n" "You can upgrade to Python 3.8+ or install typed_ast with\n"
"You can upgrade to Python 3.8+ or install typed_ast with\n" "`python3 -m pip install typed-ast`.",
"`python3 -m pip install typed-ast`."
),
file=sys.stderr, file=sys.stderr,
) )
sys.exit(1) sys.exit(1)

View File

@ -1186,19 +1186,33 @@ def _prefer_paren_wrap_match(LL: List[Leaf]) -> Optional[int]:
if LL[0].type != token.STRING: if LL[0].type != token.STRING:
return None return None
# If the string is surrounded by commas (or is the first/last child)... matching_nodes = [
prev_sibling = LL[0].prev_sibling syms.listmaker,
next_sibling = LL[0].next_sibling syms.dictsetmaker,
if not prev_sibling and not next_sibling and parent_type(LL[0]) == syms.atom: syms.testlist_gexp,
# If it's an atom string, we need to check the parent atom's siblings. ]
parent = LL[0].parent # If the string is an immediate child of a list/set/tuple literal...
assert parent is not None # For type checkers. if (
prev_sibling = parent.prev_sibling parent_type(LL[0]) in matching_nodes
next_sibling = parent.next_sibling or parent_type(LL[0].parent) in matching_nodes
if (not prev_sibling or prev_sibling.type == token.COMMA) and (
not next_sibling or next_sibling.type == token.COMMA
): ):
return 0 # And the string is surrounded by commas (or is the first/last child)...
prev_sibling = LL[0].prev_sibling
next_sibling = LL[0].next_sibling
if (
not prev_sibling
and not next_sibling
and parent_type(LL[0]) == syms.atom
):
# If it's an atom string, we need to check the parent atom's siblings.
parent = LL[0].parent
assert parent is not None # For type checkers.
prev_sibling = parent.prev_sibling
next_sibling = parent.next_sibling
if (not prev_sibling or prev_sibling.type == token.COMMA) and (
not next_sibling or next_sibling.type == token.COMMA
):
return 0
return None return None
@ -1811,8 +1825,9 @@ class StringParenWrapper(BaseStringSplitter, CustomSplitMapMixin):
* The line is an lambda expression and the value is a string. * The line is an lambda expression and the value is a string.
OR OR
* The line starts with an "atom" string that prefers to be wrapped in * The line starts with an "atom" string that prefers to be wrapped in
parens. It's preferred to be wrapped when the string is surrounded by parens. It's preferred to be wrapped when it's is an immediate child of
commas (or is the first/last child). a list/set/tuple literal, AND the string is surrounded by commas (or is
the first/last child).
Transformations: Transformations:
The chosen string is wrapped in parentheses and then split at the LPAR. The chosen string is wrapped in parentheses and then split at the LPAR.

View File

@ -79,14 +79,10 @@
) )
# long arguments # long arguments
normal_name = normal_function_name( normal_name = normal_function_name(
( "but with super long string arguments that on their own exceed the line limit so"
"but with super long string arguments that on their own exceed the line limit" " there's no way it can ever fit",
" 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",
(
"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, this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it=0,
) )
string_variable_name = "a string that is waaaaaaaayyyyyyyy too long, even in parens, there's nothing you can do" # noqa string_variable_name = "a string that is waaaaaaaayyyyyyyy too long, even in parens, there's nothing you can do" # noqa

View File

@ -323,10 +323,8 @@ def foo():
y = "Short string" y = "Short string"
print( print(
( "This is a really long string inside of a print statement with extra arguments"
"This is a really long string inside of a print statement with extra arguments" " attached at the end of it.",
" attached at the end of it."
),
x, x,
y, y,
z, z,
@ -501,15 +499,13 @@ def foo():
) )
bad_split_func1( bad_split_func1(
( "But what should happen when code has already "
"But what should happen when code has already " "been formatted but in the wrong way? Like "
"been formatted but in the wrong way? Like " "with a space at the end instead of the "
"with a space at the end instead of the " "beginning. Or what about when it is split too "
"beginning. Or what about when it is split too " "soon? In the case of a split that is too "
"soon? In the case of a split that is too " "short, black will try to honer the custom "
"short, black will try to honer the custom " "split.",
"split."
),
xxx, xxx,
yyy, yyy,
zzz, zzz,
@ -612,11 +608,9 @@ def foo():
) )
arg_comment_string = print( arg_comment_string = print(
( # This comment gets thrown to the top. "Long lines with inline comments which are apart of (and not the only member of) an"
"Long lines with inline comments which are apart of (and not the only member" " argument list should have their comments appended to the reformatted string's"
" of) an argument list should have their comments appended to the reformatted" " enclosing left parentheses.", # This comment gets thrown to the top.
" string's enclosing left parentheses."
),
"Arg #2", "Arg #2",
"Arg #3", "Arg #3",
"Arg #4", "Arg #4",
@ -676,31 +670,23 @@ def foo():
) )
func_with_bad_comma( func_with_bad_comma(
( "This is a really long string argument to a function that has a trailing comma"
"This is a really long string argument to a function that has a trailing comma" " which should NOT be there.",
" which should NOT be there."
),
) )
func_with_bad_comma( func_with_bad_comma(
( # comment after comma "This is a really long string argument to a function that has a trailing comma"
"This is a really long string argument to a function that has a trailing comma" " which should NOT be there.", # comment after comma
" which should NOT be there."
),
) )
func_with_bad_comma( func_with_bad_comma(
( "This is a really long string argument to a function that has a trailing comma"
"This is a really long string argument to a function that has a trailing comma" " which should NOT be there.",
" which should NOT be there."
),
) )
func_with_bad_comma( func_with_bad_comma(
( # comment after comma "This is a really long string argument to a function that has a trailing comma"
"This is a really long string argument to a function that has a trailing comma" " which should NOT be there.", # comment after comma
" which should NOT be there."
),
) )
func_with_bad_parens_that_wont_fit_in_one_line( func_with_bad_parens_that_wont_fit_in_one_line(

View File

@ -715,11 +715,9 @@ class A:
def foo(): def foo():
some_func_call( some_func_call(
"xxxxxxxxxx", "xxxxxxxxxx",
( "xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x "
"xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x " '"xxxx xxxxxxx xxxxxx xxxx; xxxx xxxxxx_xxxxx xxxxxx xxxx; '
'"xxxx xxxxxxx xxxxxx xxxx; xxxx xxxxxx_xxxxx xxxxxx xxxx; ' "xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" ",
"xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" "
),
None, None,
("xxxxxxxxxxx",), ("xxxxxxxxxxx",),
), ),
@ -728,11 +726,9 @@ def foo():
class A: class A:
def foo(): def foo():
some_func_call( some_func_call(
( "xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x "
"xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x " "xxxx, ('xxxxxxx xxxxxx xxxx, xxxx') xxxxxx_xxxxx xxxxxx xxxx; "
"xxxx, ('xxxxxxx xxxxxx xxxx, xxxx') xxxxxx_xxxxx xxxxxx xxxx; " "xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" ",
"xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" "
),
None, None,
("xxxxxxxxxxx",), ("xxxxxxxxxxx",),
), ),
@ -850,10 +846,8 @@ def foo():
) )
lpar_and_rpar_have_comments = func_call( # LPAR Comment lpar_and_rpar_have_comments = func_call( # LPAR Comment
( # Comma Comment "Long really ridiculous type of string that shouldn't really even exist at all. I"
"Long really ridiculous type of string that shouldn't really even exist at all." " mean commmme onnn!!!", # Comma Comment
" I mean commmme onnn!!!"
),
) # RPAR Comment ) # RPAR Comment
cmd_fstring = ( cmd_fstring = (

View File

@ -567,10 +567,8 @@ def err(msg: str, **kwargs: Any) -> None:
self.assertEqual(err_lines[-1], "error: cannot format e1: boom") self.assertEqual(err_lines[-1], "error: cannot format e1: boom")
self.assertEqual( self.assertEqual(
unstyle(str(report)), unstyle(str(report)),
( "1 file reformatted, 2 files left unchanged, 1 file failed to"
"1 file reformatted, 2 files left unchanged, 1 file failed to" " reformat.",
" reformat."
),
) )
self.assertEqual(report.return_code, 123) self.assertEqual(report.return_code, 123)
report.done(Path("f3"), black.Changed.YES) report.done(Path("f3"), black.Changed.YES)
@ -579,10 +577,8 @@ def err(msg: str, **kwargs: Any) -> None:
self.assertEqual(out_lines[-1], "reformatted f3") self.assertEqual(out_lines[-1], "reformatted f3")
self.assertEqual( self.assertEqual(
unstyle(str(report)), unstyle(str(report)),
( "2 files reformatted, 2 files left unchanged, 1 file failed to"
"2 files reformatted, 2 files left unchanged, 1 file failed to" " reformat.",
" reformat."
),
) )
self.assertEqual(report.return_code, 123) self.assertEqual(report.return_code, 123)
report.failed(Path("e2"), "boom") report.failed(Path("e2"), "boom")
@ -591,10 +587,8 @@ def err(msg: str, **kwargs: Any) -> None:
self.assertEqual(err_lines[-1], "error: cannot format e2: boom") self.assertEqual(err_lines[-1], "error: cannot format e2: boom")
self.assertEqual( self.assertEqual(
unstyle(str(report)), unstyle(str(report)),
( "2 files reformatted, 2 files left unchanged, 2 files failed to"
"2 files reformatted, 2 files left unchanged, 2 files failed to" " reformat.",
" reformat."
),
) )
self.assertEqual(report.return_code, 123) self.assertEqual(report.return_code, 123)
report.path_ignored(Path("wat"), "no match") report.path_ignored(Path("wat"), "no match")
@ -603,10 +597,8 @@ def err(msg: str, **kwargs: Any) -> None:
self.assertEqual(out_lines[-1], "wat ignored: no match") self.assertEqual(out_lines[-1], "wat ignored: no match")
self.assertEqual( self.assertEqual(
unstyle(str(report)), unstyle(str(report)),
( "2 files reformatted, 2 files left unchanged, 2 files failed to"
"2 files reformatted, 2 files left unchanged, 2 files failed to" " reformat.",
" reformat."
),
) )
self.assertEqual(report.return_code, 123) self.assertEqual(report.return_code, 123)
report.done(Path("f4"), black.Changed.NO) report.done(Path("f4"), black.Changed.NO)
@ -615,28 +607,22 @@ def err(msg: str, **kwargs: Any) -> None:
self.assertEqual(out_lines[-1], "f4 already well formatted, good job.") self.assertEqual(out_lines[-1], "f4 already well formatted, good job.")
self.assertEqual( self.assertEqual(
unstyle(str(report)), unstyle(str(report)),
( "2 files reformatted, 3 files left unchanged, 2 files failed to"
"2 files reformatted, 3 files left unchanged, 2 files failed to" " reformat.",
" reformat."
),
) )
self.assertEqual(report.return_code, 123) self.assertEqual(report.return_code, 123)
report.check = True report.check = True
self.assertEqual( self.assertEqual(
unstyle(str(report)), unstyle(str(report)),
( "2 files would be reformatted, 3 files would be left unchanged, 2"
"2 files would be reformatted, 3 files would be left unchanged, 2" " files would fail to reformat.",
" files would fail to reformat."
),
) )
report.check = False report.check = False
report.diff = True report.diff = True
self.assertEqual( self.assertEqual(
unstyle(str(report)), unstyle(str(report)),
( "2 files would be reformatted, 3 files would be left unchanged, 2"
"2 files would be reformatted, 3 files would be left unchanged, 2" " files would fail to reformat.",
" files would fail to reformat."
),
) )
def test_report_quiet(self) -> None: def test_report_quiet(self) -> None:
@ -678,10 +664,8 @@ def err(msg: str, **kwargs: Any) -> None:
self.assertEqual(err_lines[-1], "error: cannot format e1: boom") self.assertEqual(err_lines[-1], "error: cannot format e1: boom")
self.assertEqual( self.assertEqual(
unstyle(str(report)), unstyle(str(report)),
( "1 file reformatted, 2 files left unchanged, 1 file failed to"
"1 file reformatted, 2 files left unchanged, 1 file failed to" " reformat.",
" reformat."
),
) )
self.assertEqual(report.return_code, 123) self.assertEqual(report.return_code, 123)
report.done(Path("f3"), black.Changed.YES) report.done(Path("f3"), black.Changed.YES)
@ -689,10 +673,8 @@ def err(msg: str, **kwargs: Any) -> None:
self.assertEqual(len(err_lines), 1) self.assertEqual(len(err_lines), 1)
self.assertEqual( self.assertEqual(
unstyle(str(report)), unstyle(str(report)),
( "2 files reformatted, 2 files left unchanged, 1 file failed to"
"2 files reformatted, 2 files left unchanged, 1 file failed to" " reformat.",
" reformat."
),
) )
self.assertEqual(report.return_code, 123) self.assertEqual(report.return_code, 123)
report.failed(Path("e2"), "boom") report.failed(Path("e2"), "boom")
@ -701,10 +683,8 @@ def err(msg: str, **kwargs: Any) -> None:
self.assertEqual(err_lines[-1], "error: cannot format e2: boom") self.assertEqual(err_lines[-1], "error: cannot format e2: boom")
self.assertEqual( self.assertEqual(
unstyle(str(report)), unstyle(str(report)),
( "2 files reformatted, 2 files left unchanged, 2 files failed to"
"2 files reformatted, 2 files left unchanged, 2 files failed to" " reformat.",
" reformat."
),
) )
self.assertEqual(report.return_code, 123) self.assertEqual(report.return_code, 123)
report.path_ignored(Path("wat"), "no match") report.path_ignored(Path("wat"), "no match")
@ -712,10 +692,8 @@ def err(msg: str, **kwargs: Any) -> None:
self.assertEqual(len(err_lines), 2) self.assertEqual(len(err_lines), 2)
self.assertEqual( self.assertEqual(
unstyle(str(report)), unstyle(str(report)),
( "2 files reformatted, 2 files left unchanged, 2 files failed to"
"2 files reformatted, 2 files left unchanged, 2 files failed to" " reformat.",
" reformat."
),
) )
self.assertEqual(report.return_code, 123) self.assertEqual(report.return_code, 123)
report.done(Path("f4"), black.Changed.NO) report.done(Path("f4"), black.Changed.NO)
@ -723,28 +701,22 @@ def err(msg: str, **kwargs: Any) -> None:
self.assertEqual(len(err_lines), 2) self.assertEqual(len(err_lines), 2)
self.assertEqual( self.assertEqual(
unstyle(str(report)), unstyle(str(report)),
( "2 files reformatted, 3 files left unchanged, 2 files failed to"
"2 files reformatted, 3 files left unchanged, 2 files failed to" " reformat.",
" reformat."
),
) )
self.assertEqual(report.return_code, 123) self.assertEqual(report.return_code, 123)
report.check = True report.check = True
self.assertEqual( self.assertEqual(
unstyle(str(report)), unstyle(str(report)),
( "2 files would be reformatted, 3 files would be left unchanged, 2"
"2 files would be reformatted, 3 files would be left unchanged, 2" " files would fail to reformat.",
" files would fail to reformat."
),
) )
report.check = False report.check = False
report.diff = True report.diff = True
self.assertEqual( self.assertEqual(
unstyle(str(report)), unstyle(str(report)),
( "2 files would be reformatted, 3 files would be left unchanged, 2"
"2 files would be reformatted, 3 files would be left unchanged, 2" " files would fail to reformat.",
" files would fail to reformat."
),
) )
def test_report_normal(self) -> None: def test_report_normal(self) -> None:
@ -788,10 +760,8 @@ def err(msg: str, **kwargs: Any) -> None:
self.assertEqual(err_lines[-1], "error: cannot format e1: boom") self.assertEqual(err_lines[-1], "error: cannot format e1: boom")
self.assertEqual( self.assertEqual(
unstyle(str(report)), unstyle(str(report)),
( "1 file reformatted, 2 files left unchanged, 1 file failed to"
"1 file reformatted, 2 files left unchanged, 1 file failed to" " reformat.",
" reformat."
),
) )
self.assertEqual(report.return_code, 123) self.assertEqual(report.return_code, 123)
report.done(Path("f3"), black.Changed.YES) report.done(Path("f3"), black.Changed.YES)
@ -800,10 +770,8 @@ def err(msg: str, **kwargs: Any) -> None:
self.assertEqual(out_lines[-1], "reformatted f3") self.assertEqual(out_lines[-1], "reformatted f3")
self.assertEqual( self.assertEqual(
unstyle(str(report)), unstyle(str(report)),
( "2 files reformatted, 2 files left unchanged, 1 file failed to"
"2 files reformatted, 2 files left unchanged, 1 file failed to" " reformat.",
" reformat."
),
) )
self.assertEqual(report.return_code, 123) self.assertEqual(report.return_code, 123)
report.failed(Path("e2"), "boom") report.failed(Path("e2"), "boom")
@ -812,10 +780,8 @@ def err(msg: str, **kwargs: Any) -> None:
self.assertEqual(err_lines[-1], "error: cannot format e2: boom") self.assertEqual(err_lines[-1], "error: cannot format e2: boom")
self.assertEqual( self.assertEqual(
unstyle(str(report)), unstyle(str(report)),
( "2 files reformatted, 2 files left unchanged, 2 files failed to"
"2 files reformatted, 2 files left unchanged, 2 files failed to" " reformat.",
" reformat."
),
) )
self.assertEqual(report.return_code, 123) self.assertEqual(report.return_code, 123)
report.path_ignored(Path("wat"), "no match") report.path_ignored(Path("wat"), "no match")
@ -823,10 +789,8 @@ def err(msg: str, **kwargs: Any) -> None:
self.assertEqual(len(err_lines), 2) self.assertEqual(len(err_lines), 2)
self.assertEqual( self.assertEqual(
unstyle(str(report)), unstyle(str(report)),
( "2 files reformatted, 2 files left unchanged, 2 files failed to"
"2 files reformatted, 2 files left unchanged, 2 files failed to" " reformat.",
" reformat."
),
) )
self.assertEqual(report.return_code, 123) self.assertEqual(report.return_code, 123)
report.done(Path("f4"), black.Changed.NO) report.done(Path("f4"), black.Changed.NO)
@ -834,28 +798,22 @@ def err(msg: str, **kwargs: Any) -> None:
self.assertEqual(len(err_lines), 2) self.assertEqual(len(err_lines), 2)
self.assertEqual( self.assertEqual(
unstyle(str(report)), unstyle(str(report)),
( "2 files reformatted, 3 files left unchanged, 2 files failed to"
"2 files reformatted, 3 files left unchanged, 2 files failed to" " reformat.",
" reformat."
),
) )
self.assertEqual(report.return_code, 123) self.assertEqual(report.return_code, 123)
report.check = True report.check = True
self.assertEqual( self.assertEqual(
unstyle(str(report)), unstyle(str(report)),
( "2 files would be reformatted, 3 files would be left unchanged, 2"
"2 files would be reformatted, 3 files would be left unchanged, 2" " files would fail to reformat.",
" files would fail to reformat."
),
) )
report.check = False report.check = False
report.diff = True report.diff = True
self.assertEqual( self.assertEqual(
unstyle(str(report)), unstyle(str(report)),
( "2 files would be reformatted, 3 files would be left unchanged, 2"
"2 files would be reformatted, 3 files would be left unchanged, 2" " files would fail to reformat.",
" files would fail to reformat."
),
) )
def test_lib2to3_parse(self) -> None: def test_lib2to3_parse(self) -> None: