Skip to content

Commit 95bca0f

Browse files
authored
Merge branch 'main' into cm
2 parents a81d7b4 + 18fb884 commit 95bca0f

File tree

14 files changed

+253
-8
lines changed

14 files changed

+253
-8
lines changed

.flake8

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[flake8]
22
# B905 should be enabled when we drop support for 3.9
3-
ignore = E203, E266, E501, W503, B905
3+
ignore = E203, E266, E501, W503, B905, B907
44
# line length is intentionally set to 80 here because black uses Bugbear
55
# See https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#line-length for more details
66
max-line-length = 80

CHANGES.md

+5
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,12 @@
3232
- Long values in dict literals are now wrapped in parentheses; correspondingly
3333
unnecessary parentheses around short values in dict literals are now removed; long
3434
string lambda values are now wrapped in parentheses (#3440)
35+
- Fix two crashes in preview style involving edge cases with docstrings (#3451)
3536
- Exclude string type annotations from improved string processing; fix crash when the
3637
return type annotation is stringified and spans across multiple lines (#3462)
3738
- Wrap multiple context managers in parentheses when targeting Python 3.9+ (#3489)
39+
- Fix several crashes in preview style with walrus operators used in `with` statements
40+
or tuples (#3473)
3841

3942
### Configuration
4043

@@ -64,6 +67,8 @@
6467

6568
- Verbose logging now shows the values of `pyproject.toml` configuration variables
6669
(#3392)
70+
- Fix false symlink detection messages in verbose output due to using an incorrect
71+
relative path to the project root (#3385)
6772

6873
### _Blackd_
6974

docs/integrations/editors.md

+106
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,19 @@ Options include the following:
1010

1111
## PyCharm/IntelliJ IDEA
1212

13+
There are three different ways you can use _Black_ from PyCharm:
14+
15+
1. As local server using the BlackConnect plugin
16+
1. As external tool
17+
1. As file watcher
18+
19+
The first option is the simplest to set up and formats the fastest (by spinning up
20+
{doc}`Black's HTTP server </usage_and_configuration/black_as_a_server>`, avoiding the
21+
startup cost on subsequent formats), but if you would prefer to not install a
22+
third-party plugin or blackd's extra dependencies, the other two are also great options.
23+
24+
### As local server
25+
1326
1. Install _Black_ with the `d` extra.
1427

1528
```console
@@ -46,6 +59,99 @@ Options include the following:
4659
- In `Trigger Settings` section of plugin configuration check
4760
`Trigger when saving changed files`.
4861

62+
### As external tool
63+
64+
1. Install `black`.
65+
66+
```console
67+
$ pip install black
68+
```
69+
70+
1. Locate your `black` installation folder.
71+
72+
On macOS / Linux / BSD:
73+
74+
```console
75+
$ which black
76+
/usr/local/bin/black # possible location
77+
```
78+
79+
On Windows:
80+
81+
```console
82+
$ where black
83+
%LocalAppData%\Programs\Python\Python36-32\Scripts\black.exe # possible location
84+
```
85+
86+
Note that if you are using a virtual environment detected by PyCharm, this is an
87+
unneeded step. In this case the path to `black` is `$PyInterpreterDirectory$/black`.
88+
89+
1. Open External tools in PyCharm/IntelliJ IDEA
90+
91+
On macOS:
92+
93+
`PyCharm -> Preferences -> Tools -> External Tools`
94+
95+
On Windows / Linux / BSD:
96+
97+
`File -> Settings -> Tools -> External Tools`
98+
99+
1. Click the + icon to add a new external tool with the following values:
100+
101+
- Name: Black
102+
- Description: Black is the uncompromising Python code formatter.
103+
- Program: \<install_location_from_step_2>
104+
- Arguments: `"$FilePath$"`
105+
106+
1. Format the currently opened file by selecting `Tools -> External Tools -> black`.
107+
108+
- Alternatively, you can set a keyboard shortcut by navigating to
109+
`Preferences or Settings -> Keymap -> External Tools -> External Tools - Black`.
110+
111+
### As file watcher
112+
113+
1. Install `black`.
114+
115+
```console
116+
$ pip install black
117+
```
118+
119+
1. Locate your `black` installation folder.
120+
121+
On macOS / Linux / BSD:
122+
123+
```console
124+
$ which black
125+
/usr/local/bin/black # possible location
126+
```
127+
128+
On Windows:
129+
130+
```console
131+
$ where black
132+
%LocalAppData%\Programs\Python\Python36-32\Scripts\black.exe # possible location
133+
```
134+
135+
Note that if you are using a virtual environment detected by PyCharm, this is an
136+
unneeded step. In this case the path to `black` is `$PyInterpreterDirectory$/black`.
137+
138+
1. Make sure you have the
139+
[File Watchers](https://plugins.jetbrains.com/plugin/7177-file-watchers) plugin
140+
installed.
141+
1. Go to `Preferences or Settings -> Tools -> File Watchers` and click `+` to add a new
142+
watcher:
143+
- Name: Black
144+
- File type: Python
145+
- Scope: Project Files
146+
- Program: \<install_location_from_step_2>
147+
- Arguments: `$FilePath$`
148+
- Output paths to refresh: `$FilePath$`
149+
- Working directory: `$ProjectFileDir$`
150+
151+
- In Advanced Options
152+
- Uncheck "Auto-save edited files to trigger the watcher"
153+
- Uncheck "Trigger the watcher on external changes"
154+
49155
## Wing IDE
50156

51157
Wing IDE supports `black` via **Preference Settings** for system wide settings and

docs/the_black_code_style/future_style.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ with make_context_manager1() as cm1, make_context_manager2() as cm2, make_contex
1919
... # nothing to split on - line too long
2020
```
2121

22-
So _Black_ will eventually format it like this:
22+
So _Black_ will, when we implement this, format it like this:
2323

2424
```py3
2525
with \
@@ -31,8 +31,8 @@ with \
3131
... # backslashes and an ugly stranded colon
3232
```
3333

34-
Although when the target version is Python 3.9 or higher, _Black_ will use parentheses
35-
instead since they're allowed in Python 3.9 and higher.
34+
Although when the target version is Python 3.9 or higher, _Black_ will, when we
35+
implement this, use parentheses instead since they're allowed in Python 3.9 and higher.
3636

3737
An alternative to consider if the backslashes in the above formatting are undesirable is
3838
to use {external:py:obj}`contextlib.ExitStack` to combine context managers in the

docs/usage_and_configuration/the_basics.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ so style options are deliberately limited and rarely added.
4040

4141
</details>
4242

43+
Note that all command-line options listed above can also be configured using a
44+
`pyproject.toml` file (more on that below).
45+
4346
### Code input alternatives
4447

4548
#### Standard Input
@@ -287,9 +290,6 @@ file hierarchy.
287290

288291
## Next steps
289292

290-
You've probably noted that not all of the options you can pass to _Black_ have been
291-
covered. Don't worry, the rest will be covered in a later section.
292-
293293
A good next step would be configuring auto-discovery so `black .` is all you need
294294
instead of laborously listing every file or directory. You can get started by heading
295295
over to [File collection and discovery](./file_collection_and_discovery.md).

src/black/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -673,10 +673,11 @@ def get_sources(
673673

674674
sources.add(p)
675675
elif p.is_dir():
676+
p = root / normalize_path_maybe_ignore(p, ctx.obj["root"], report)
676677
if using_default_exclude:
677678
gitignore = {
678679
root: root_gitignore,
679-
root / p: get_gitignore(p),
680+
p: get_gitignore(p),
680681
}
681682
sources.update(
682683
gen_python_files(

src/black/linegen.py

+8
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
is_rpar_token,
4747
is_stub_body,
4848
is_stub_suite,
49+
is_tuple_containing_walrus,
4950
is_vararg,
5051
is_walrus_assignment,
5152
is_yield,
@@ -406,6 +407,7 @@ def visit_STRING(self, leaf: Leaf) -> Iterator[Line]:
406407
else:
407408
docstring = docstring.strip()
408409

410+
has_trailing_backslash = False
409411
if docstring:
410412
# Add some padding if the docstring starts / ends with a quote mark.
411413
if docstring[0] == quote_char:
@@ -418,6 +420,7 @@ def visit_STRING(self, leaf: Leaf) -> Iterator[Line]:
418420
# Odd number of tailing backslashes, add some padding to
419421
# avoid escaping the closing string quote.
420422
docstring += " "
423+
has_trailing_backslash = True
421424
elif not docstring_started_empty:
422425
docstring = " "
423426

@@ -440,6 +443,8 @@ def visit_STRING(self, leaf: Leaf) -> Iterator[Line]:
440443
if (
441444
len(lines) > 1
442445
and last_line_length + quote_len > self.mode.line_length
446+
and len(indent) + quote_len <= self.mode.line_length
447+
and not has_trailing_backslash
443448
):
444449
leaf.value = prefix + quote + docstring + "\n" + indent + quote
445450
else:
@@ -1336,6 +1341,7 @@ def maybe_make_parens_invisible_in_atom(
13361341
not remove_brackets_around_comma
13371342
and max_delimiter_priority_in_atom(node) >= COMMA_PRIORITY
13381343
)
1344+
or is_tuple_containing_walrus(node)
13391345
):
13401346
return False
13411347

@@ -1347,9 +1353,11 @@ def maybe_make_parens_invisible_in_atom(
13471353
syms.return_stmt,
13481354
syms.except_clause,
13491355
syms.funcdef,
1356+
syms.with_stmt,
13501357
# these ones aren't useful to end users, but they do please fuzzers
13511358
syms.for_stmt,
13521359
syms.del_stmt,
1360+
syms.for_stmt,
13531361
]:
13541362
return False
13551363

src/black/nodes.py

+11
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,17 @@ def is_one_tuple(node: LN) -> bool:
563563
)
564564

565565

566+
def is_tuple_containing_walrus(node: LN) -> bool:
567+
"""Return True if `node` holds a tuple that contains a walrus operator."""
568+
if node.type != syms.atom:
569+
return False
570+
gexp = unwrap_singleton_parenthesis(node)
571+
if gexp is None or gexp.type != syms.testlist_gexp:
572+
return False
573+
574+
return any(child.type == syms.namedexpr_test for child in gexp.children)
575+
576+
566577
def is_one_sequence_between(
567578
opening: Leaf,
568579
closing: Leaf,

tests/data/fast/pep_572_do_not_remove_parens.py

+4
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,7 @@
1919
@(please := stop)
2020
def sigh():
2121
pass
22+
23+
24+
for (x := 3, y := 4) in y:
25+
pass
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Regression test for #3427, which reproes only with line length <= 6
2+
def f():
3+
"""
4+
x
5+
"""

tests/data/py_38/pep_572_remove_parens.py

+40
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,26 @@ def a():
4949
def this_is_so_dumb() -> (please := no):
5050
pass
5151

52+
async def await_the_walrus():
53+
with (x := y):
54+
pass
55+
56+
with (x := y) as z, (a := b) as c:
57+
pass
58+
59+
with (x := await y):
60+
pass
61+
62+
with (x := await a, y := await b):
63+
pass
64+
65+
# Ideally we should remove one set of parentheses
66+
with ((x := await a, y := await b)):
67+
pass
68+
69+
with (x := await a), (y := await b):
70+
pass
71+
5272

5373
# output
5474
if foo := 0:
@@ -103,3 +123,23 @@ def a():
103123
def this_is_so_dumb() -> (please := no):
104124
pass
105125

126+
127+
async def await_the_walrus():
128+
with (x := y):
129+
pass
130+
131+
with (x := y) as z, (a := b) as c:
132+
pass
133+
134+
with (x := await y):
135+
pass
136+
137+
with (x := await a, y := await b):
138+
pass
139+
140+
# Ideally we should remove one set of parentheses
141+
with ((x := await a, y := await b)):
142+
pass
143+
144+
with (x := await a), (y := await b):
145+
pass

tests/data/simple_cases/docstring.py

+11
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,11 @@ def multiline_backslash_2():
173173
'''
174174
hey there \ '''
175175

176+
# Regression test for #3425
177+
def multiline_backslash_really_long_dont_crash():
178+
"""
179+
hey there hello guten tag hi hoow are you ola zdravstvuyte ciao como estas ca va \ """
180+
176181

177182
def multiline_backslash_3():
178183
'''
@@ -391,6 +396,12 @@ def multiline_backslash_2():
391396
hey there \ """
392397

393398

399+
# Regression test for #3425
400+
def multiline_backslash_really_long_dont_crash():
401+
"""
402+
hey there hello guten tag hi hoow are you ola zdravstvuyte ciao como estas ca va \ """
403+
404+
394405
def multiline_backslash_3():
395406
"""
396407
already escaped \\"""

0 commit comments

Comments
 (0)