Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrap concatenated strings used as function args in parens. #3307

Merged
merged 7 commits into from Oct 27, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES.md
Expand Up @@ -14,7 +14,11 @@

<!-- Changes that affect Black's preview style -->

- Fix a crash when formatting some dicts with parenthesis-wrapped long string keys
(#3262)
JelleZijlstra marked this conversation as resolved.
Show resolved Hide resolved
- Enforce empty lines before classes and functions with sticky leading comments (#3302)
- Implicitly concatenated strings used as function args are now wrapped inside
parentheses (#3307)

### Configuration

Expand Down
6 changes: 4 additions & 2 deletions src/black/__init__.py
Expand Up @@ -497,8 +497,10 @@ def main( # noqa: C901
user_level_config = str(find_user_pyproject_toml())
if config == user_level_config:
out(
"Using configuration from user-level config at "
f"'{user_level_config}'.",
(
"Using configuration from user-level config at "
f"'{user_level_config}'."
),
fg="blue",
)
elif config_source in (
Expand Down
6 changes: 4 additions & 2 deletions src/black/mode.py
Expand Up @@ -180,8 +180,10 @@ class Mode:
def __post_init__(self) -> None:
if self.experimental_string_processing:
warn(
"`experimental string processing` has been included in `preview`"
" and deprecated. Use `preview` instead.",
(
"`experimental string processing` has been included in `preview`"
" and deprecated. Use `preview` instead."
),
Deprecated,
)

Expand Down
8 changes: 5 additions & 3 deletions src/black/parsing.py
Expand Up @@ -29,9 +29,11 @@
except ImportError:
if sys.version_info < (3, 8) and not _IS_PYPY:
print(
"The typed_ast package is required but not installed.\n"
"You can upgrade to Python 3.8+ or install typed_ast with\n"
"`python3 -m pip install typed-ast`.",
(
"The typed_ast package is required but not installed.\n"
"You can upgrade to Python 3.8+ or install typed_ast with\n"
"`python3 -m pip install typed-ast`."
),
file=sys.stderr,
)
sys.exit(1)
Expand Down
1 change: 1 addition & 0 deletions src/black/trans.py
Expand Up @@ -1062,6 +1062,7 @@ def _prefer_paren_wrap_match(LL: List[Leaf]) -> Optional[int]:
syms.listmaker,
syms.dictsetmaker,
syms.testlist_gexp,
syms.arglist,
]
# If the string is an immediate child of a list/set/tuple literal...
yilei marked this conversation as resolved.
Show resolved Hide resolved
if (
Expand Down
12 changes: 8 additions & 4 deletions tests/data/preview/cantfit.py
Expand Up @@ -79,10 +79,14 @@
)
# long arguments
normal_name = normal_function_name(
"but with super long string arguments that on their own exceed the line limit 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",
(
"but with super long string arguments that on their own exceed the line limit"
" 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"
),
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
Expand Down
54 changes: 34 additions & 20 deletions tests/data/preview/long_strings.py
Expand Up @@ -297,8 +297,10 @@ def foo():
y = "Short string"

print(
"This is a really long string inside of a print statement with extra arguments"
" attached at the end of it.",
(
"This is a really long string inside of a print statement with extra arguments"
" attached at the end of it."
),
x,
y,
z,
Expand Down Expand Up @@ -474,13 +476,15 @@ def foo():
)

bad_split_func1(
"But what should happen when code has already "
"been formatted but in the wrong way? Like "
"with a space at the end instead of the "
"beginning. Or what about when it is split too "
"soon? In the case of a split that is too "
"short, black will try to honer the custom "
"split.",
(
"But what should happen when code has already "
"been formatted but in the wrong way? Like "
"with a space at the end instead of the "
"beginning. Or what about when it is split too "
"soon? In the case of a split that is too "
"short, black will try to honer the custom "
"split."
),
xxx,
yyy,
zzz,
Expand Down Expand Up @@ -583,9 +587,11 @@ def foo():
)

arg_comment_string = print(
"Long lines with inline comments which are apart of (and not the only member of) an"
" argument list should have their comments appended to the reformatted string's"
" enclosing left parentheses.", # This comment gets thrown to the top.
( # This comment gets thrown to the top.
"Long lines with inline comments which are apart of (and not the only member"
" of) an argument list should have their comments appended to the reformatted"
" string's enclosing left parentheses."
),
"Arg #2",
"Arg #3",
"Arg #4",
Expand Down Expand Up @@ -645,23 +651,31 @@ def foo():
)

func_with_bad_comma(
"This is a really long string argument to a function that has a trailing comma"
" which should NOT be there.",
(
"This is a really long string argument to a function that has a trailing comma"
" which should NOT be there."
),
)

func_with_bad_comma(
"This is a really long string argument to a function that has a trailing comma"
" which should NOT be there.", # comment after comma
( # comment after comma
"This is a really long string argument to a function that has a trailing comma"
" which should NOT be there."
),
)

func_with_bad_comma(
"This is a really long string argument to a function that has a trailing comma"
" which should NOT be there.",
(
"This is a really long string argument to a function that has a trailing comma"
" which should NOT be there."
),
)

func_with_bad_comma(
"This is a really long string argument to a function that has a trailing comma"
" which should NOT be there.", # comment after comma
( # comment after comma
"This is a really long string argument to a function that has a trailing comma"
" which should NOT be there."
),
)

func_with_bad_parens_that_wont_fit_in_one_line(
Expand Down
22 changes: 14 additions & 8 deletions tests/data/preview/long_strings__regression.py
Expand Up @@ -679,9 +679,11 @@ class A:
def foo():
some_func_call(
"xxxxxxxxxx",
"xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x "
'"xxxx xxxxxxx xxxxxx xxxx; xxxx xxxxxx_xxxxx xxxxxx xxxx; '
"xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" ",
(
"xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x "
'"xxxx xxxxxxx xxxxxx xxxx; xxxx xxxxxx_xxxxx xxxxxx xxxx; '
"xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" "
),
None,
("xxxxxxxxxxx",),
),
Expand All @@ -690,9 +692,11 @@ def foo():
class A:
def foo():
some_func_call(
"xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x "
"xxxx, ('xxxxxxx xxxxxx xxxx, xxxx') xxxxxx_xxxxx xxxxxx xxxx; "
"xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" ",
(
"xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x "
"xxxx, ('xxxxxxx xxxxxx xxxx, xxxx') xxxxxx_xxxxx xxxxxx xxxx; "
"xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" "
),
None,
("xxxxxxxxxxx",),
),
Expand Down Expand Up @@ -810,8 +814,10 @@ def foo():
)

lpar_and_rpar_have_comments = func_call( # LPAR Comment
"Long really ridiculous type of string that shouldn't really even exist at all. I"
" mean commmme onnn!!!", # Comma Comment
( # Comma Comment
"Long really ridiculous type of string that shouldn't really even exist at all."
" I mean commmme onnn!!!"
),
) # RPAR Comment

cmd_fstring = (
Expand Down