Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions src/docformatter/classify.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,19 +343,23 @@ def is_f_string(token: tokenize.TokenInfo, prev_token: tokenize.TokenInfo) -> bo
bool
True if the token is an f-string, False otherwise.
"""
# On Python 3.12+, PEP 701 tokenizes an f-string as a FSTRING_START /
# FSTRING_MIDDLE / FSTRING_END sequence, so adjacent tokens must be
# stitched back together onto the same row.
if PY312:
if tokenize.FSTRING_MIDDLE in [token.type, prev_token.type]:
return True
elif any(
[
token.string.startswith('f"""'),
prev_token.string.startswith('f"""'),
token.string.startswith("f'''"),
prev_token.string.startswith("f'''"),
]
):
return True

return False

# Before Python 3.12, an f-string is always tokenized as a single STRING
# token, so there is nothing to stitch together and this function should
# never fire. Naively checking the string prefix here (regardless of
# bracket/assignment context) used to misclassify *any* f\"\"\"/f''' token
# -- e.g. one nested inside a parenthesized expression or tuple -- as
# needing row-continuation treatment, corrupting the row bookkeeping in
# ``_get_unmatched_start_end_indices`` and causing
# ``tokenize.untokenize`` to raise ``ValueError`` (see issue #367).
return False


Expand Down
14 changes: 14 additions & 0 deletions tests/_data/string_files/do_format_code.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1260,3 +1260,17 @@ expected="def foo():\n \"\"\"Summary.\"\"\"\n x = 1\n # next line has 4
[issue_360_no_trailing_newline]
source="def foo():\n \"\"\"\n Hello foo.\n \"\"\"\n x = 1"
expected="def foo():\n \"\"\"Hello foo.\"\"\"\n x = 1"

[issue_367]
source='''def build(x):
return (
f"""a
{x}""",
)
'''
expected='''def build(x):
return (
f"""a
{x}""",
)
'''
1 change: 1 addition & 0 deletions tests/formatter/test_do_format_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@
("issue_331_black_module_docstring", ["--black", ""]),
("issue_355", NO_ARGS),
("issue_360_no_trailing_newline", NO_ARGS),
("issue_367", NO_ARGS),
],
)
def test_do_format_code(test_key, test_args, args):
Expand Down