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:
parent
0abe85eebb
commit
4e3303fa08
@ -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
|
||||
|
@ -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
|
||||
]
|
||||
)
|
||||
|
@ -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.
|
||||
|
@ -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()
|
||||
|
||||
|
160
tests/data/conditional_expression.py
Normal file
160
tests/data/conditional_expression.py
Normal 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
|
||||
)
|
Loading…
Reference in New Issue
Block a user