d0aab9212a
fuzz / fuzz (3.11) (push) Failing after 1s
fuzz / fuzz (3.12) (push) Failing after 1s
build and publish / sdist + pure wheel (push) Failing after 0s
diff-shades / analysis / base / ${{ matrix.mode }} (push) Has been skipped
docs / docs (ubuntu-latest) (push) Failing after 2s
fuzz / fuzz (3.10) (push) Failing after 1s
fuzz / fuzz (3.14) (push) Failing after 0s
lint and format / lint (push) Failing after 1s
diff-shades / configure (push) Failing after 1s
docker / build (linux/amd64) (push) Has been skipped
diff-shades / analysis / target / ${{ matrix.mode }} (push) Has been skipped
fuzz / fuzz (3.13) (push) Failing after 0s
build and publish / generate wheels matrix (push) Failing after 0s
test release tool / test-release-tool (ubuntu-latest, 3.13) (push) Failing after 1s
build and publish / mypyc wheels ${{ matrix.only }} (push) Has been skipped
test / test (ubuntu-latest, 3.10) (push) Failing after 0s
test / test (ubuntu-latest, 3.11) (push) Failing after 1s
test / test (ubuntu-latest, 3.13) (push) Failing after 0s
test / test (ubuntu-latest, pypy3.11-v7.3.22) (push) Failing after 1s
test / test (ubuntu-latest, 3.15) (push) Failing after 1s
test release tool / test-release-tool (ubuntu-latest, 3.15) (push) Failing after 0s
zizmor / zizmor (push) Failing after 0s
test release tool / test-release-tool (ubuntu-latest, 3.12) (push) Failing after 4s
test release tool / test-release-tool (ubuntu-latest, 3.14) (push) Failing after 3s
test / uvloop (ubuntu-latest) (push) Failing after 1s
test / test (ubuntu-latest, 3.14) (push) Failing after 1s
test / test (ubuntu-latest, 3.12.10) (push) Failing after 5s
docker / build (linux/arm64) (push) Has been cancelled
docker / push (push) Has been cancelled
docs / docs (windows-latest) (push) Has been cancelled
test release tool / test-release-tool (windows-latest, 3.14) (push) Has been cancelled
test release tool / test-release-tool (windows-latest, 3.15) (push) Has been cancelled
test release tool / test-release-tool (macOS-latest, 3.12) (push) Has been cancelled
test release tool / test-release-tool (macOS-latest, 3.13) (push) Has been cancelled
test release tool / test-release-tool (macOS-latest, 3.14) (push) Has been cancelled
test release tool / test-release-tool (macOS-latest, 3.15) (push) Has been cancelled
test release tool / test-release-tool (windows-latest, 3.12) (push) Has been cancelled
test release tool / test-release-tool (windows-latest, 3.13) (push) Has been cancelled
test / test (macOS-latest, 3.11) (push) Has been cancelled
test / test (macOS-latest, 3.12.10) (push) Has been cancelled
test / test (macOS-latest, 3.13) (push) Has been cancelled
test / test (macOS-latest, 3.14) (push) Has been cancelled
test / test (macOS-latest, 3.15) (push) Has been cancelled
test / test (macOS-latest, pypy3.11-v7.3.22) (push) Has been cancelled
test / test (windows-11-arm, 3.11) (push) Has been cancelled
test / test (windows-11-arm, 3.12.10) (push) Has been cancelled
test / test (windows-11-arm, 3.13) (push) Has been cancelled
test / test (macOS-latest, 3.10) (push) Has been cancelled
test / coveralls-finish (push) Has been cancelled
test / uvloop (macOS-latest) (push) Has been cancelled
test / uvloop (windows-11-arm) (push) Has been cancelled
test / uvloop (windows-latest) (push) Has been cancelled
test / test (windows-11-arm, 3.14) (push) Has been cancelled
test / test (windows-11-arm, 3.15) (push) Has been cancelled
test / test (windows-latest, 3.10) (push) Has been cancelled
test / test (windows-latest, 3.11) (push) Has been cancelled
test / test (windows-latest, 3.12.10) (push) Has been cancelled
test / test (windows-latest, 3.13) (push) Has been cancelled
test / test (windows-latest, 3.14) (push) Has been cancelled
test / test (windows-latest, 3.15) (push) Has been cancelled
test / test (windows-latest, pypy3.11-v7.3.22) (push) Has been cancelled
diff-shades / compare / ${{ matrix.mode }} (push) Has been cancelled
fuzz / create-issue (push) Has been cancelled
build and publish / publish-mypyc (push) Has been cancelled
build and publish / publish-hatch (push) Has been cancelled
501 lines
14 KiB
Markdown
501 lines
14 KiB
Markdown
# The (future of the) Black code style
|
|
|
|
## Preview style
|
|
|
|
(labels/preview-style)=
|
|
|
|
Experimental, potentially disruptive style changes are gathered under the `--preview`
|
|
CLI flag. At the end of each year, these changes may be adopted into the default style,
|
|
as described in [The Black Code Style](index.md). Because the functionality is
|
|
experimental, feedback and issue reports are highly encouraged!
|
|
|
|
(labels/preview-features)=
|
|
|
|
Currently, the following features are included in the preview style:
|
|
|
|
- `wrap_comprehension_in`: Wrap the `in` clause of list and dictionary comprehensions
|
|
across lines if it would otherwise exceed the maximum line length.
|
|
([see below](labels/wrap-comprehension-in))
|
|
- `simplify_power_operator_hugging`: Use a simpler implementation of the power operator
|
|
"hugging" logic (removing whitespace around `**` in simple expressions), which applies
|
|
also in the rare case the exponentiation is split into separate lines.
|
|
([see below](labels/simplify-power-operator))
|
|
- `wrap_long_dict_values_in_parens`: Add parentheses around long values in dictionaries.
|
|
([see below](labels/wrap-long-dict-values))
|
|
- `fix_if_guard_explosion_in_case_statement`: fixed exploding of the if guard in case
|
|
patterns which have trailing commas in them, even if the guard expression fits in one
|
|
line
|
|
- `pyi_overload_group_blank_lines`: In `.pyi` stub files, improve heuristics around when
|
|
blank lines should appear before, after and within decorated function groups.
|
|
([see below](labels/pyi-overload-group))
|
|
- `pyi_blank_line_before_decorated_class`: In `.pyi` stub files, enforce a blank line
|
|
before a decorated class definition when it follows a function definition.
|
|
([see below](labels/pyi-blank-line-before-decorated-class))
|
|
- `fix_unnecessary_parens_in_indexed_assignment`: Remove unnecessary parentheses around
|
|
the right-hand side of indexed assignments (e.g. `x[key] = expr`) when the subscripted
|
|
target is too long to fit on one line and the expression fits on the tail line.
|
|
([see below](labels/fix-unnecessary-parens-indexed-assignment))
|
|
- `pyi_blank_line_after_function_docstring`: In `.pyi` stub files, enforce a blank line
|
|
after a function or method body that consists of a docstring.
|
|
([see below](labels/pyi-blank-line-after-function-docstring))
|
|
- `hug_comparator`: Don't break a comparator (`not in`, `==`, `is`, ...) away from its
|
|
left operand when the right operand is a bracketed expression that has to break
|
|
anyway; let the bracket explode instead. ([see below](labels/hug-comparator))
|
|
- `parenthesize_tuple_in_yield`: Add parentheses around tuple expressions in `yield`
|
|
statements.
|
|
|
|
(labels/wrap-comprehension-in)=
|
|
|
|
### Wrapping long comprehension `in` clauses
|
|
|
|
When a list or dictionary comprehension has a long `in` clause that would exceed the
|
|
maximum line length, Black will wrap it across multiple lines for better readability.
|
|
This helps keep comprehensions readable when the iterable expression is complex or
|
|
lengthy.
|
|
|
|
For example:
|
|
|
|
```python
|
|
# Before
|
|
result = [
|
|
very_very_very_very_very_long_item
|
|
for very_very_very_very_very_long_item in some_very_very_very_very_very_very_long_function_name
|
|
]
|
|
```
|
|
|
|
will be formatted to:
|
|
|
|
```python
|
|
# After
|
|
result = [
|
|
very_very_very_very_very_long_item
|
|
for very_very_very_very_very_long_item in (
|
|
some_very_very_very_very_very_very_long_function_name
|
|
)
|
|
]
|
|
```
|
|
|
|
This also applies to dictionary comprehensions:
|
|
|
|
```python
|
|
# Before
|
|
mapping = {
|
|
very_long_key: very_very_very_long_item
|
|
for very_long_key, very_very_very_long_item in very_very_very_very_long_function_name
|
|
}
|
|
```
|
|
|
|
will be formatted to:
|
|
|
|
```python
|
|
# After
|
|
mapping = {
|
|
very_long_key: very_very_very_long_item
|
|
for very_long_key, very_very_very_long_item in (
|
|
very_very_very_very_long_function_name
|
|
)
|
|
}
|
|
```
|
|
|
|
(labels/simplify-power-operator)=
|
|
|
|
### Simplified power operator whitespace handling
|
|
|
|
Black's power operator "hugging" logic removes whitespace around `**` in simple
|
|
expressions (e.g., `x**2` instead of `x ** 2`). This feature uses a simpler, more
|
|
consistent implementation that also applies when exponentiation is split across lines.
|
|
|
|
For example:
|
|
|
|
```python
|
|
# Simple expressions - whitespace is removed
|
|
result = x**2 + y**3
|
|
value = base**exponent
|
|
```
|
|
|
|
When the exponentiation is split across lines (rare), the simplified logic ensures
|
|
consistent formatting:
|
|
|
|
```python
|
|
# Complex expression split across lines
|
|
result = (
|
|
some_very_long_base_expression
|
|
**some_very_long_exponent_expression
|
|
**some_very_long_third_expression
|
|
)
|
|
```
|
|
|
|
This feature primarily improves the internal consistency of Black's formatting logic
|
|
rather than making dramatic visual changes to most code.
|
|
|
|
(labels/wrap-long-dict-values)=
|
|
|
|
### Improved parentheses management in dicts
|
|
|
|
For dict literals with long values, they are now wrapped in parentheses. Unnecessary
|
|
parentheses are now removed. For example:
|
|
|
|
```python
|
|
my_dict = {
|
|
"a key in my dict": a_very_long_variable
|
|
* and_a_very_long_function_call()
|
|
/ 100000.0,
|
|
"another key": (short_value),
|
|
}
|
|
```
|
|
|
|
will be changed to:
|
|
|
|
```python
|
|
my_dict = {
|
|
"a key in my dict": (
|
|
a_very_long_variable * and_a_very_long_function_call() / 100000.0
|
|
),
|
|
"another key": short_value,
|
|
}
|
|
```
|
|
|
|
(labels/pyi-overload-group)=
|
|
|
|
### Improved overload groups in stub files
|
|
|
|
In `.pyi` stub files, Black now has improved heuristics regarding when blank lines
|
|
should appear before, after or within groups of decorated functions that share the same
|
|
name (such as `@overload` groups). Two rules are applied when a decorated function is
|
|
determined to be part of a series of >=2 decorated functions with the same name:
|
|
|
|
1. **Before the decorated function**: a blank line is always inserted, unless the
|
|
preceding statement is a same-name decorated function (i.e. part of an `@overload`
|
|
group) or the function is the first statement in its block.
|
|
2. **After the decorated function**: a blank line is always inserted, unless the
|
|
following statement is a same-name decorated function.
|
|
|
|
These rules apply regardless of what the adjacent statement is — whether it's another
|
|
function definition, a variable annotation, or any other statement.
|
|
|
|
Previously, Black could insert unwanted blank lines _within_ an overload group when one
|
|
of the overloads had a docstring, and did not consistently enforce blank lines at the
|
|
boundaries of overload groups:
|
|
|
|
```python
|
|
# Before
|
|
|
|
@overload
|
|
def foo(x: int) -> int:
|
|
"""Docs."""
|
|
|
|
@overload # unwanted blank line within group
|
|
def foo(x: str) -> str: ...
|
|
def bar(x): ... # no blank line after group
|
|
```
|
|
|
|
With this feature enabled, the group is kept together and clearly separated from
|
|
surrounding code:
|
|
|
|
```python
|
|
# After (with --preview)
|
|
|
|
@overload
|
|
def foo(x: int) -> int:
|
|
"""Docs."""
|
|
@overload
|
|
def foo(x: str) -> str: ...
|
|
|
|
def bar(x): ...
|
|
```
|
|
|
|
(labels/pyi-blank-line-before-decorated-class)=
|
|
|
|
### Blank line before decorated classes in stub files
|
|
|
|
In `.pyi` stub files, Black already enforces blank lines around class definitions in
|
|
many situations. However, when a class has a decorator, Black previously failed to
|
|
enforce this, instead _removing_ the blank line between a function and the decorator:
|
|
|
|
```diff
|
|
# Before
|
|
|
|
def foo(): ...
|
|
-
|
|
@decorator
|
|
class Bar: ...
|
|
|
|
def baz(): ...
|
|
@decorator
|
|
class Spam: ...
|
|
```
|
|
|
|
With this feature enabled, a blank line is enforced, consistent with how undecorated
|
|
classes are handled:
|
|
|
|
```diff
|
|
# After (with --preview)
|
|
|
|
def foo(): ...
|
|
|
|
@decorator
|
|
class Bar: ...
|
|
|
|
def baz(): ...
|
|
+
|
|
@decorator
|
|
class Spam: ...
|
|
```
|
|
|
|
(labels/fix-unnecessary-parens-indexed-assignment)=
|
|
|
|
### Unnecessary parentheses in indexed assignments
|
|
|
|
When an assignment target ends with a subscript (e.g. `x[key] = expr`) and is too long
|
|
to fit on one line, Black has to split at the subscript's brackets. Previously it would
|
|
additionally wrap the right-hand side expression in parentheses, even when the
|
|
expression fits on the closing line. With this feature enabled, Black omits those
|
|
unnecessary parentheses.
|
|
|
|
For example:
|
|
|
|
```python
|
|
# Before
|
|
dictionary_of_arrays["long_key_name_for_the_example"][
|
|
very_long_index_name, index_zero
|
|
] = (10 - 5)
|
|
```
|
|
|
|
will be formatted to:
|
|
|
|
```python
|
|
# After (with --preview)
|
|
dictionary_of_arrays["long_key_name_for_the_example"][
|
|
very_long_index_name, index_zero
|
|
] = 10 - 5
|
|
```
|
|
|
|
Assignments whose target fits on one line are not affected: wrapping the right-hand side
|
|
in parentheses remains the preferred style there.
|
|
|
|
(labels/pyi-blank-line-after-function-docstring)=
|
|
|
|
### Blank line after function docstrings in stub files
|
|
|
|
In `.pyi` stub files, functions and methods sometimes use a docstring as their whole
|
|
body. Black already separated these definitions from a following function definition,
|
|
but did not consistently do the same before a following comment, conditional block,
|
|
variable annotation, or other statement:
|
|
|
|
```python
|
|
# Before
|
|
|
|
class Example:
|
|
def method(self) -> None:
|
|
"""Documentation."""
|
|
# comment for the next member
|
|
attr: int
|
|
```
|
|
|
|
With this feature enabled, the docstring-only function body is consistently separated
|
|
from the next comment or statement:
|
|
|
|
```python
|
|
# After (with --preview)
|
|
|
|
class Example:
|
|
def method(self) -> None:
|
|
"""Documentation."""
|
|
|
|
# comment for the next member
|
|
attr: int
|
|
```
|
|
|
|
Black still keeps same-name decorated functions, such as `@overload` groups and property
|
|
setters, together without inserting blank lines between them.
|
|
|
|
(labels/hug-comparator)=
|
|
|
|
### Keep comparators next to their left operand
|
|
|
|
When a comparator (`not in`, `==`, `is`, ...) sits inside another bracketed construct
|
|
and its right operand is a bracketed expression that has to break (either via a magic
|
|
trailing comma or because the line is too long), Black used to split the line right
|
|
before the comparator. The left operand ended up alone on its own line, visually
|
|
disconnected from the operator and the operand that explains it:
|
|
|
|
```python
|
|
# Before
|
|
|
|
x = [
|
|
t
|
|
for t in y
|
|
if t
|
|
not in {
|
|
LongNameOne,
|
|
LongNameTwo,
|
|
LongNameThree,
|
|
}
|
|
]
|
|
```
|
|
|
|
With this feature enabled, Black skips that comparator split and lets the right-hand
|
|
bracket explode instead, which it would have done anyway:
|
|
|
|
```python
|
|
# After (with --preview)
|
|
|
|
x = [
|
|
t
|
|
for t in y
|
|
if t not in {
|
|
LongNameOne,
|
|
LongNameTwo,
|
|
LongNameThree,
|
|
}
|
|
]
|
|
```
|
|
|
|
The fix is not limited to comprehensions. The same shape appears inside `if`/`elif`
|
|
chains, `assert` statements, and parenthesized expressions, and gets the same treatment:
|
|
|
|
```python
|
|
# Before
|
|
|
|
if (
|
|
is_scalar(value)
|
|
and self.dtype
|
|
in (np.dtype("float64"), np.dtype("float32"), np.dtype("object"))
|
|
and (limit is not None or inplace)
|
|
):
|
|
...
|
|
|
|
assert (
|
|
bool
|
|
is _AnnotationExtractor(attr.fields(C).x.converter.__call__).get_return_type()
|
|
)
|
|
```
|
|
|
|
```python
|
|
# After (with --preview)
|
|
|
|
if (
|
|
is_scalar(value)
|
|
and self.dtype in (
|
|
np.dtype("float64"),
|
|
np.dtype("float32"),
|
|
np.dtype("object"),
|
|
)
|
|
and (limit is not None or inplace)
|
|
):
|
|
...
|
|
|
|
assert (
|
|
bool is _AnnotationExtractor(
|
|
attr.fields(C).x.converter.__call__
|
|
).get_return_type()
|
|
)
|
|
```
|
|
|
|
## Unstable style
|
|
|
|
(labels/unstable-style)=
|
|
|
|
In the past, the preview style included some features with known bugs, so that we were
|
|
unable to move these features to the stable style. Therefore, such features are now
|
|
moved to the `--unstable` style. All features in the `--preview` style are expected to
|
|
make it to next year's stable style; features in the `--unstable` style will be
|
|
stabilized only if issues with them are fixed. If bugs are discovered in a `--preview`
|
|
feature, it is demoted to the `--unstable` style. To avoid thrash when a feature is
|
|
demoted from the `--preview` to the `--unstable` style, users can use the
|
|
`--enable-unstable-feature` flag to enable specific unstable features.
|
|
|
|
(labels/unstable-features)=
|
|
|
|
The unstable style additionally includes the following features:
|
|
|
|
- `hug_parens_with_braces_and_square_brackets`: More compact formatting of nested
|
|
brackets. ([see below](labels/hug-parens))
|
|
- `string_processing`: Split long string literals and related changes.
|
|
([see below](labels/string-processing))
|
|
|
|
(labels/hug-parens)=
|
|
|
|
### Improved multiline dictionary and list indentation for sole function parameter
|
|
|
|
For better readability and less verticality, _Black_ now pairs parentheses ("(", ")")
|
|
with braces ("{", "}") and square brackets ("[", "]") on the same line. For example:
|
|
|
|
```python
|
|
foo(
|
|
[
|
|
1,
|
|
2,
|
|
3,
|
|
]
|
|
)
|
|
|
|
nested_array = [
|
|
[
|
|
1,
|
|
2,
|
|
3,
|
|
]
|
|
]
|
|
```
|
|
|
|
will be changed to:
|
|
|
|
```python
|
|
foo([
|
|
1,
|
|
2,
|
|
3,
|
|
])
|
|
|
|
nested_array = [[
|
|
1,
|
|
2,
|
|
3,
|
|
]]
|
|
```
|
|
|
|
This also applies to list and dictionary unpacking:
|
|
|
|
```python
|
|
foo(
|
|
*[
|
|
a_long_function_name(a_long_variable_name)
|
|
for a_long_variable_name in some_generator
|
|
]
|
|
)
|
|
```
|
|
|
|
will become:
|
|
|
|
```python
|
|
foo(*[
|
|
a_long_function_name(a_long_variable_name)
|
|
for a_long_variable_name in some_generator
|
|
])
|
|
```
|
|
|
|
You can use a magic trailing comma to avoid this compacting behavior; by default,
|
|
_Black_ will not reformat the following code:
|
|
|
|
```python
|
|
foo(
|
|
[
|
|
1,
|
|
2,
|
|
3,
|
|
],
|
|
)
|
|
```
|
|
|
|
(labels/string-processing)=
|
|
|
|
### Improved string processing
|
|
|
|
_Black_ will split long string literals and merge short ones. Parentheses are used where
|
|
appropriate. When split, parts of f-strings that don't need formatting are converted to
|
|
plain strings. f-strings will not be merged if they contain internal quotes and it would
|
|
change their quotation mark style. Line continuation backslashes are converted into
|
|
parenthesized strings. Unnecessary parentheses are stripped. The stability and status of
|
|
this feature is tracked in [this issue](https://github.com/psf/black/issues/2188).
|