Skip to content

Commit 7316aac

Browse files
authored
Merge pull request #747 from hhatto/fix-e501-experimental-fstring
Fix e501 experimental fstring case in Python3.12+
2 parents afd79c2 + 6f5f04d commit 7316aac

2 files changed

Lines changed: 37 additions & 7 deletions

File tree

autopep8.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,10 @@ class documentation for more information.
154154

155155
MAX_PYTHON_FILE_DETECTION_BYTES = 1024
156156

157+
IS_SUPPORT_TOKEN_FSTRING = False
158+
if sys.version_info >= (3, 12): # pgrama: no cover
159+
IS_SUPPORT_TOKEN_FSTRING = True
160+
157161

158162
def open_with_encoding(filename, mode='r', encoding=None, limit_byte_check=-1):
159163
"""Return opened file with a specific encoding."""
@@ -2045,6 +2049,7 @@ def __init__(self, max_line_length):
20452049
self._bracket_depth = 0
20462050
self._prev_item = None
20472051
self._prev_prev_item = None
2052+
self._in_fstring = False
20482053

20492054
def __repr__(self):
20502055
return self.emit()
@@ -2172,6 +2177,11 @@ def _add_item(self, item, indent_amt):
21722177
inserted inside of a container or not.
21732178
21742179
"""
2180+
if item.is_fstring_start:
2181+
self._in_fstring = True
2182+
elif self._prev_item and self._prev_item.is_fstring_end:
2183+
self._in_fstring = False
2184+
21752185
if self._prev_item and self._prev_item.is_string and item.is_string:
21762186
# Place consecutive string literals on separate lines.
21772187
self._lines.append(self._LineBreak())
@@ -2198,10 +2208,10 @@ def _add_item(self, item, indent_amt):
21982208
self._lines.append(item)
21992209
self._prev_item, self._prev_prev_item = item, self._prev_item
22002210

2201-
if item_text in '([{':
2211+
if item_text in '([{' and not self._in_fstring:
22022212
self._bracket_depth += 1
22032213

2204-
elif item_text in '}])':
2214+
elif item_text in '}])' and not self._in_fstring:
22052215
self._bracket_depth -= 1
22062216
assert self._bracket_depth >= 0
22072217

@@ -2400,6 +2410,18 @@ def is_keyword(self):
24002410
def is_string(self):
24012411
return self._atom.token_type == tokenize.STRING
24022412

2413+
@property
2414+
def is_fstring_start(self):
2415+
if not IS_SUPPORT_TOKEN_FSTRING:
2416+
return False
2417+
return self._atom.token_type == tokenize.FSTRING_START
2418+
2419+
@property
2420+
def is_fstring_end(self):
2421+
if not IS_SUPPORT_TOKEN_FSTRING:
2422+
return False
2423+
return self._atom.token_type == tokenize.FSTRING_END
2424+
24032425
@property
24042426
def is_name(self):
24052427
return self._atom.token_type == tokenize.NAME

test/test_autopep8.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3948,7 +3948,7 @@ def test_e701_with_escaped_newline(self):
39483948
with autopep8_context(line) as result:
39493949
self.assertEqual(fixed, result)
39503950

3951-
@unittest.skipIf(sys.version_info >= (3, 12), 'not detech in Python3.12+')
3951+
@unittest.skipIf(sys.version_info >= (3, 12), 'not detect in Python3.12+')
39523952
def test_e701_with_escaped_newline_and_spaces(self):
39533953
line = 'if True: \\ \nprint(True)\n'
39543954
fixed = 'if True:\n print(True)\n'
@@ -4446,7 +4446,7 @@ def test_e731_with_default_arguments(self):
44464446
with autopep8_context(line, options=['--select=E731']) as result:
44474447
self.assertEqual(fixed, result)
44484448

4449-
@unittest.skipIf(sys.version_info >= (3, 12), 'not detech in Python3.12+')
4449+
@unittest.skipIf(sys.version_info >= (3, 12), 'not detect in Python3.12+')
44504450
def test_e901_should_cause_indentation_screw_up(self):
44514451
line = """\
44524452
def tmp(g):
@@ -5495,7 +5495,7 @@ def test_help(self):
54955495
stdout=PIPE)
54965496
self.assertIn('usage:', p.communicate()[0].decode('utf-8').lower())
54975497

5498-
@unittest.skipIf(sys.version_info >= (3, 12), 'not detech in Python3.12+')
5498+
@unittest.skipIf(sys.version_info >= (3, 12), 'not detect in Python3.12+')
54995499
def test_verbose(self):
55005500
line = 'bad_syntax)'
55015501
with temporary_file_context(line) as filename:
@@ -7236,7 +7236,7 @@ def f(self):
72367236
with autopep8_context(line, options=['--experimental']) as result:
72377237
self.assertEqual(fixed, result)
72387238

7239-
@unittest.skipIf(sys.version_info >= (3, 12), 'not detech in Python3.12+')
7239+
@unittest.skipIf(sys.version_info >= (3, 12), 'not detect in Python3.12+')
72407240
def test_e501_experimental_parsing_dict_with_comments(self):
72417241
line = """\
72427242
self.display['xxxxxxxxxxxx'] = [{'title': _('Library'), #. This is the first comment.
@@ -7260,7 +7260,7 @@ def test_e501_experimental_parsing_dict_with_comments(self):
72607260
with autopep8_context(line, options=['--experimental']) as result:
72617261
self.assertEqual(fixed, result)
72627262

7263-
@unittest.skipIf(sys.version_info >= (3, 12), 'not detech in Python3.12+')
7263+
@unittest.skipIf(sys.version_info >= (3, 12), 'not detect in Python3.12+')
72647264
def test_e501_experimental_if_line_over_limit(self):
72657265
line = """\
72667266
if not xxxxxxxxxxxx(aaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbb, cccccccccccccc, dddddddddddddddddddddd):
@@ -7333,6 +7333,14 @@ def test_e501_experimental_with_in(self):
73337333
with autopep8_context(line, options=['--experimental']) as result:
73347334
self.assertEqual(fixed, result)
73357335

7336+
@unittest.skipIf(sys.version_info < (3, 12), 'not support in Python3.11 and lower version')
7337+
def test_e501_experimental_not_effect_with_fstring(self):
7338+
line = """\
7339+
fstring = {"some_key": f"There is a string value inside of an f string, which itself is a dictionary value {s})"}
7340+
"""
7341+
with autopep8_context(line, options=['--experimental']) as result:
7342+
self.assertEqual(line, result)
7343+
73367344

73377345
def fix_e266(source):
73387346
with autopep8_context(source, options=['--select=E266']) as result:

0 commit comments

Comments
 (0)