Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6064a43

Browse files
authored
Use debug f-strings for feature detection (psf#3215)
Fixes psfGH-2907.
1 parent 507234c commit 6064a43

4 files changed

Lines changed: 34 additions & 0 deletions

File tree

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333

3434
<!-- Changes to how Black can be configured -->
3535

36+
- Black now uses the presence of debug f-strings to detect target version. (#3215)
37+
3638
### Documentation
3739

3840
<!-- Major changes to documentation and policies. Small docs changes

src/black/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
from black.parsing import InvalidInput # noqa F401
8888
from black.parsing import lib2to3_parse, parse_ast, stringify_ast
8989
from black.report import Changed, NothingChanged, Report
90+
from black.trans import iter_fexpr_spans
9091
from blib2to3.pgen2 import token
9192
from blib2to3.pytree import Leaf, Node
9293

@@ -1240,6 +1241,7 @@ def get_features_used( # noqa: C901
12401241
12411242
Currently looking for:
12421243
- f-strings;
1244+
- self-documenting expressions in f-strings (f"{x=}");
12431245
- underscores in numeric literals;
12441246
- trailing commas after * or ** in function signatures and calls;
12451247
- positional only arguments in function signatures and lambdas;
@@ -1261,6 +1263,11 @@ def get_features_used( # noqa: C901
12611263
value_head = n.value[:2]
12621264
if value_head in {'f"', 'F"', "f'", "F'", "rf", "fr", "RF", "FR"}:
12631265
features.add(Feature.F_STRINGS)
1266+
if Feature.DEBUG_F_STRINGS not in features:
1267+
for span_beg, span_end in iter_fexpr_spans(n.value):
1268+
if n.value[span_beg : span_end - 1].rstrip().endswith("="):
1269+
features.add(Feature.DEBUG_F_STRINGS)
1270+
break
12641271

12651272
elif is_number_token(n):
12661273
if "_" in n.value:

src/black/mode.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class Feature(Enum):
4949
ANN_ASSIGN_EXTENDED_RHS = 13
5050
EXCEPT_STAR = 14
5151
VARIADIC_GENERICS = 15
52+
DEBUG_F_STRINGS = 16
5253
FORCE_OPTIONAL_PARENTHESES = 50
5354

5455
# __future__ flags
@@ -81,6 +82,7 @@ class Feature(Enum):
8182
},
8283
TargetVersion.PY38: {
8384
Feature.F_STRINGS,
85+
Feature.DEBUG_F_STRINGS,
8486
Feature.NUMERIC_UNDERSCORES,
8587
Feature.TRAILING_COMMA_IN_CALL,
8688
Feature.TRAILING_COMMA_IN_DEF,
@@ -93,6 +95,7 @@ class Feature(Enum):
9395
},
9496
TargetVersion.PY39: {
9597
Feature.F_STRINGS,
98+
Feature.DEBUG_F_STRINGS,
9699
Feature.NUMERIC_UNDERSCORES,
97100
Feature.TRAILING_COMMA_IN_CALL,
98101
Feature.TRAILING_COMMA_IN_DEF,
@@ -106,6 +109,7 @@ class Feature(Enum):
106109
},
107110
TargetVersion.PY310: {
108111
Feature.F_STRINGS,
112+
Feature.DEBUG_F_STRINGS,
109113
Feature.NUMERIC_UNDERSCORES,
110114
Feature.TRAILING_COMMA_IN_CALL,
111115
Feature.TRAILING_COMMA_IN_DEF,
@@ -120,6 +124,7 @@ class Feature(Enum):
120124
},
121125
TargetVersion.PY311: {
122126
Feature.F_STRINGS,
127+
Feature.DEBUG_F_STRINGS,
123128
Feature.NUMERIC_UNDERSCORES,
124129
Feature.TRAILING_COMMA_IN_CALL,
125130
Feature.TRAILING_COMMA_IN_DEF,

tests/test_black.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,26 @@ def test_detect_pos_only_arguments(self) -> None:
310310
versions = black.detect_target_versions(root)
311311
self.assertIn(black.TargetVersion.PY38, versions)
312312

313+
def test_detect_debug_f_strings(self) -> None:
314+
root = black.lib2to3_parse("""f"{x=}" """)
315+
features = black.get_features_used(root)
316+
self.assertIn(black.Feature.DEBUG_F_STRINGS, features)
317+
versions = black.detect_target_versions(root)
318+
self.assertIn(black.TargetVersion.PY38, versions)
319+
320+
root = black.lib2to3_parse(
321+
"""f"{x}"\nf'{"="}'\nf'{(x:=5)}'\nf'{f(a="3=")}'\nf'{x:=10}'\n"""
322+
)
323+
features = black.get_features_used(root)
324+
self.assertNotIn(black.Feature.DEBUG_F_STRINGS, features)
325+
326+
# We don't yet support feature version detection in nested f-strings
327+
root = black.lib2to3_parse(
328+
"""f"heard a rumour that { f'{1+1=}' } ... seems like it could be true" """
329+
)
330+
features = black.get_features_used(root)
331+
self.assertNotIn(black.Feature.DEBUG_F_STRINGS, features)
332+
313333
@patch("black.dump_to_file", dump_to_stderr)
314334
def test_string_quotes(self) -> None:
315335
source, expected = read_data("miscellaneous", "string_quotes")

0 commit comments

Comments
 (0)