1.7.8 crashes with a tokenize ValueError on a multi-line f-string inside parentheses
Los mantenedores suelen responder en 1 día
@adityaanikam ya está trabajando en esto.
Desde el 10/8/2026.
Evaluación
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Aptitud para principiantes
- 74/100
Línea de trabajo
Comienza con classify.is_f_string y su consumidor _get_unmatched_start_end_indices en format.py:499-535, y luego ejecuta el reproductor suministrado de f-string multilínea en Python 3.11. Sigue cómo la comprobación de f-string anterior a 3.12 cambia la fila de inicio del token; el trabajo estará terminado cuando el reproductor se formatee sin ValueError y las ejecuciones con varios archivos no se aborten con esta entrada.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
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
fprefix 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.
- Lenguaje dominante
- Python
- Estrellas
- 598
- Forks
- 95
- Merge medio
- 2 d 3 h
- PR fusionados (30 d)
- 11
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de PyCQA/docformatter
-
1.7.8 rewrites the contents of a non-docstring triple-quoted string, silently changing its valueAbiertoC: convention P: bug U: high
Dificultad 3/5 1-2 días Aptitud para principiantes 72/100
PyCQA/docformatter#366 ·
Los mantenedores suelen responder en 1 día
-
C: stakeholder P: enhancement U: low
Dificultad 3/5 1-2 días Aptitud para principiantes 65/100
PyCQA/docformatter#346 ·
Los mantenedores suelen responder en 1 día
-
C: convention P: bug U: high
Dificultad 3/5 1-2 días Aptitud para principiantes 48/100
PyCQA/docformatter#345 · 1 reacción ·
Los mantenedores suelen responder en 1 día
-
C: convention P: bug U: high
Dificultad 3/5 1-2 días Aptitud para principiantes 55/100
PyCQA/docformatter#315 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
C: convention help wanted P: bug U: high
Dificultad 3/5 1-2 días Aptitud para principiantes 35/100
PyCQA/docformatter#285 · 3 comentarios ·
Los mantenedores suelen responder en 1 día
Todos los issues de PyCQA/docformatter
Issues similares
-
Deferred from #1869: Complete the companion pytest guardrail update noted in the PR description...Abierto
Dificultad 1/5 Menos de una hora Aptitud para principiantes 95/100
Los mantenedores suelen responder en 1 día
-
Custom provider API keys collide on one host: env slot keyed on host:port only, not URL pathAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
NousResearch/hermes-agent#140958 ·
Los mantenedores suelen responder en 1 día
-
Bug triage/confirmed
Dificultad 2/5 Medio día Aptitud para principiantes 85/100
agentscope-ai/agentscope#3355 ·
Los mantenedores suelen responder en 2 días
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 95/100
ethereum/execution-specs#3859 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 1 día