Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

1.7.8 crashes with a tokenize ValueError on a multi-line f-string inside parentheses

オープン
#367 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

@adityaanikam がすでに取り組んでいます。

2026年8月10日 から。

評価

難易度
3/5
見積もり時間
1〜2日
初心者へのやさしさ
74/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
静か
技術スタック
python
領域
tooling

調査の方向性

format.py:499-535 の classify.is_f_string とその consumer である _get_unmatched_start_end_indices から始め、続いて提供された複数行 f-string の再現コードを Python 3.11 で実行します。3.12 より前の f-string チェックによって token の開始行がどのように変わるかを追跡します。この入力で再現コードが ValueError なしにフォーマットされ、複数ファイルでの実行が中断されなければ完了です。

索引モデルが issue の本文から書いたものです。

説明

C: convention P: bug U: high

docformatter 1.7.8 aborts with a ValueError out of tokenize.untokenize when a file contains a multi-line f-string inside a parenthesized expression. 1.7.7 formats the same file cleanly.

Reproducer

def build(x):
    return (
        f"""a
{x}""",
    )
$ docformatter --in-place t.py
  File ".../docformatter/format.py", line 876, in _do_format_code
    _code = tokenize.untokenize(self.new_tokens)
  File "/usr/lib/python3.11/tokenize.py", line 216, in untokenize
    self.add_whitespace(start)
  File "/usr/lib/python3.11/tokenize.py", line 177, in add_whitespace
    raise ValueError("start ({},{}) precedes previous end ({},{})"
ValueError: start (2,8) precedes previous end (3,4)
$ echo $?
1

No config file and no flags are needed. Two things narrow it:

  • Remove the f prefix and the run exits 3 (would reformat) with no error, so the f-string prefix is the trigger.
  • Assign the same f-string to a name instead of putting it in a tuple and it does not crash, so it has to sit inside parentheses.

Affected versions

docformatter Python 3.11 Python 3.12 Python 3.13
1.7.7 ok ok ok
1.7.8 ValueError ok ok
master ValueError ok ok

Root cause

Bisected to d9ace1f ("fix: resolve several empty line regressions", #330). Its parent 7798699 is clean.

That commit adds a Python < 3.12 workaround to classify.is_f_string:

elif any(
    [
        token.string.startswith('f"""'),
        prev_token.string.startswith('f"""'),
        token.string.startswith("f'''"),
        prev_token.string.startswith("f'''"),
    ]
):
    return True

The PY312 branch above it tests tokenize.FSTRING_MIDDLE, which only appears inside an f-string. The < 3.12 branch instead matches any token whose text begins with f""", including an ordinary triple-quoted f-string that is not a docstring — and, via prev_token, the token that follows one.

The single consumer is _get_unmatched_start_end_indices (format.py:499), where a true verdict sets _start_row = prev_token.end[0] (format.py:526-535). That rewrites the f-string's start row back to where the previous token ended, so untokenize sees a token starting above one it has already emitted and raises.

Impact

With several files on one command line, the run aborts at the first offending file and exits 1, leaving every file after it unprocessed. On a 1,255-file tree this stopped at file 318 with no indication that the remainder was skipped.

Environment

CPython 3.11.15, Linux x86-64, docformatter==1.7.8 from PyPI.

主要言語
Python
スター
598
フォーク
97
平均マージ
1日 8時間
マージ済み PR(30日)
11

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

PyCQA/docformatter のほかの issue

PyCQA/docformatter の issue をすべて見る

似ている issue

Python の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。