Parenthesize conditional expressions (#2278)

Co-authored-by: Jordan Ephron <JEphron@users.noreply.github.com>
Co-authored-by: Richard Si <63936253+ichard26@users.noreply.github.com>
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
This commit is contained in:
Jordan Ephron 2022-12-29 18:13:15 -05:00 committed by GitHub
parent 0abe85eebb
commit 4e3303fa08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 188 additions and 6 deletions

View File

@ -16,6 +16,7 @@
<!-- Changes that affect Black's preview style -->
- Add parentheses around `if`-`else` expressions (#2278)
- Improve the performance on large expressions that contain many strings (#3467)
- Fix a crash in preview style with assert + parenthesized string (#3415)
- Fix crashes in preview style with walrus operators used in function return annotations

View File

@ -478,16 +478,20 @@ def main( # noqa: C901
)
normalized = [
(
(source, source)
if source == "-"
else (normalize_path_maybe_ignore(Path(source), root), source)
)
for source in src
]
srcs_string = ", ".join(
[
(
f'"{_norm}"'
if _norm
else f'\033[31m"{source} (skipping - invalid)"\033[34m'
)
for _norm, source in normalized
]
)

View File

@ -140,6 +140,22 @@ def visit_default(self, node: LN) -> Iterator[Line]:
self.current_line.append(node)
yield from super().visit_default(node)
def visit_test(self, node: Node) -> Iterator[Line]:
"""Visit an `x if y else z` test"""
if Preview.parenthesize_conditional_expressions in self.mode:
already_parenthesized = (
node.prev_sibling and node.prev_sibling.type == token.LPAR
)
if not already_parenthesized:
lpar = Leaf(token.LPAR, "")
rpar = Leaf(token.RPAR, "")
node.insert_child(0, lpar)
node.append_child(rpar)
yield from self.visit_default(node)
def visit_INDENT(self, node: Leaf) -> Iterator[Line]:
"""Increase indentation level, maybe yield a line."""
# In blib2to3 INDENT never holds comments.

View File

@ -161,6 +161,7 @@ class Preview(Enum):
# NOTE: string_processing requires wrap_long_dict_values_in_parens
# for https://github.com/psf/black/issues/3117 to be fixed.
string_processing = auto()
parenthesize_conditional_expressions = auto()
skip_magic_trailing_comma_in_subscript = auto()
wrap_long_dict_values_in_parens = auto()

View File

@ -0,0 +1,160 @@
long_kwargs_single_line = my_function(
foo="test, this is a sample value",
bar=some_long_value_name_foo_bar_baz if some_boolean_variable else some_fallback_value_foo_bar_baz,
baz="hello, this is a another value",
)
multiline_kwargs_indented = my_function(
foo="test, this is a sample value",
bar=some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz,
baz="hello, this is a another value",
)
imploding_kwargs = my_function(
foo="test, this is a sample value",
bar=a
if foo
else b,
baz="hello, this is a another value",
)
imploding_line = (
1
if 1 + 1 == 2
else 0
)
exploding_line = "hello this is a slightly long string" if some_long_value_name_foo_bar_baz else "this one is a little shorter"
positional_argument_test(some_long_value_name_foo_bar_baz if some_boolean_variable else some_fallback_value_foo_bar_baz)
def weird_default_argument(x=some_long_value_name_foo_bar_baz
if SOME_CONSTANT
else some_fallback_value_foo_bar_baz):
pass
nested = "hello this is a slightly long string" if (some_long_value_name_foo_bar_baz if
nesting_test_expressions else some_fallback_value_foo_bar_baz) \
else "this one is a little shorter"
generator_expression = (
some_long_value_name_foo_bar_baz if some_boolean_variable else some_fallback_value_foo_bar_baz for some_boolean_variable in some_iterable
)
def limit_offset_sql(self, low_mark, high_mark):
"""Return LIMIT/OFFSET SQL clause."""
limit, offset = self._get_limit_offset_params(low_mark, high_mark)
return " ".join(
sql
for sql in (
"LIMIT %d" % limit if limit else None,
("OFFSET %d" % offset) if offset else None,
)
if sql
)
def something():
clone._iterable_class = (
NamedValuesListIterable
if named
else FlatValuesListIterable
if flat
else ValuesListIterable
)
# output
long_kwargs_single_line = my_function(
foo="test, this is a sample value",
bar=(
some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz
),
baz="hello, this is a another value",
)
multiline_kwargs_indented = my_function(
foo="test, this is a sample value",
bar=(
some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz
),
baz="hello, this is a another value",
)
imploding_kwargs = my_function(
foo="test, this is a sample value",
bar=a if foo else b,
baz="hello, this is a another value",
)
imploding_line = 1 if 1 + 1 == 2 else 0
exploding_line = (
"hello this is a slightly long string"
if some_long_value_name_foo_bar_baz
else "this one is a little shorter"
)
positional_argument_test(
some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz
)
def weird_default_argument(
x=(
some_long_value_name_foo_bar_baz
if SOME_CONSTANT
else some_fallback_value_foo_bar_baz
),
):
pass
nested = (
"hello this is a slightly long string"
if (
some_long_value_name_foo_bar_baz
if nesting_test_expressions
else some_fallback_value_foo_bar_baz
)
else "this one is a little shorter"
)
generator_expression = (
(
some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz
)
for some_boolean_variable in some_iterable
)
def limit_offset_sql(self, low_mark, high_mark):
"""Return LIMIT/OFFSET SQL clause."""
limit, offset = self._get_limit_offset_params(low_mark, high_mark)
return " ".join(
sql
for sql in (
"LIMIT %d" % limit if limit else None,
("OFFSET %d" % offset) if offset else None,
)
if sql
)
def something():
clone._iterable_class = (
NamedValuesListIterable
if named
else FlatValuesListIterable if flat else ValuesListIterable
)