docformatter deadlock with ruff-format: blank lines around nested definitions
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Aptitud para principiantes
- 68/100
Línea de trabajo
Comienza con las reproducciones mínimas en example.py y example_class.py, y luego ejecuta docformatter y ruff format con las configuraciones mostradas para reproducir ambos bucles. Rastrea cómo docformatter clasifica las líneas en blanco después de docstrings anidados de una sola línea y añade cobertura de regresión para los dos casos. El trabajo estará terminado cuando las ejecuciones repetidas converjan sin que ninguna de las dos herramientas deshaga los cambios de la otra.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Summary
docformatter and ruff-format enter an infinite correction loop in pre-commit when
test functions contain nested def or class definitions whose only body is a one-line
docstring. The tools disagree on whether a blank line should follow the nested definition,
so each tool's output is the other tool's input and pre-commit never converges.
Two distinct sub-issues are present:
- Loop A — nested
defwith one-liner docstring: docformatter removes the blank line
after it; ruff-format adds it back. - Loop B — nested
classwith one-liner docstring (blank = truein config): docformatter
adds an extra blank line; ruff-format removes it.
Versions
| Tool | Version |
|---|---|
| docformatter (pip / pre-commit hook) | 1.7.8 |
ruff-format (pre-commit hook astral-sh/ruff-pre-commit) |
v0.15.9 |
| Python | 3.10.11 |
Configuration
pyproject.toml:
[tool.docformatter]
recursive = true
wrap-summaries = 120
wrap-descriptions = 120
blank = true
.pre-commit-config.yaml (relevant hooks):
- repo: https://github.com/PyCQA/docformatter
rev: v1.7.8
hooks:
- id: docformatter
language_version: python3.10
additional_dependencies: [tomli]
args: ["--in-place"]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.9
hooks:
- id: ruff-check
args: ["--fix"]
- id: ruff-format
Minimal reproduction — Loop A
Create example.py:
def outer() -> None:
"""Outer function."""
def inner() -> None:
"""One-liner docstring."""
next_statement = 1
Run docformatter:
docformatter --in-place --blank example.py
Result — blank line removed:
def outer() -> None:
"""Outer function."""
def inner() -> None:
"""One-liner docstring."""
next_statement = 1 # ← blank line gone
Run ruff-format on that output:
ruff format example.py
Result — blank line restored (back to original):
def outer() -> None:
"""Outer function."""
def inner() -> None:
"""One-liner docstring."""
next_statement = 1 # ← blank line back
Running both again repeats the cycle indefinitely.
Minimal reproduction — Loop B (blank = true)
Create example_class.py:
def outer() -> None:
"""Outer function."""
class Inner:
"""One-liner class docstring."""
@some_decorator
class Another:
"""Another class."""
With blank = true, docformatter inserts an extra blank line after the one-liner
class docstring (before @some_decorator), producing two consecutive blank lines.
ruff-format then removes the extra one. Each tool undoes the other.
Root cause
Loop A
docformatter interprets the blank line between the closing """ of inner()'s docstring
and next_statement as being inside inner()'s function body and removes it as a
PEP 257 D202 violation ("no blank lines allowed after function docstring").
The blank line is not inside inner() — it is in the outer scope, separating two
statements. docformatter misattributes it because the last token of inner()'s body is
the closing """ of a one-liner docstring on the same line as the opening """, with no
other body statements.
ruff-format (Black-compatible) correctly requires the blank line between the nested
definition and the following statement per E301 / PEP 8.
Loop B
blank = true causes docformatter to insert a blank line at the end of one-liner class
docstrings when they are followed by another definition. Combined with the blank line
already present, this produces two blank lines (E303), which ruff-format then reduces
back to one.
Expected behaviour
docformatter should not remove the blank line that follows a nested function definition
whose only body is a one-liner docstring. That blank line belongs to the enclosing
scope, not to the nested function.
Workaround
Remove blank = true from [tool.docformatter] to mitigate Loop B.
Loop A has no configuration-level workaround; the only option is to exclude the affected
files from docformatter or avoid the nested-def-with-one-liner-docstring pattern in test
code.
- Lenguaje dominante
- Python
- Estrellas
- 598
- Forks
- 93
- Métricas de merge de PR
- Sin PR fusionados en 30 d
Preparar el entorno
Aún no hemos revisado los archivos de configuración de este proyecto. 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
-
fresh
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
PyCQA/docformatter#383 ·
-
fresh
Dificultad 3/5 1-2 días Aptitud para principiantes 78/100
PyCQA/docformatter#385 ·
-
fresh
Dificultad 3/5 1-2 días Aptitud para principiantes 72/100
PyCQA/docformatter#379 ·
-
fresh
Dificultad 3/5 1-2 días Aptitud para principiantes 68/100
PyCQA/docformatter#377 ·
-
C: convention P: bug U: high
Dificultad 3/5 1-2 días Aptitud para principiantes 74/100
PyCQA/docformatter#367 · 1 comentario ·
Todos los issues de PyCQA/docformatter
Issues similares
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
Los mantenedores suelen responder en 1 día
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 90/100
Los mantenedores suelen responder en 1 día
-
https://search.utilibre.orgAbiertoinstance instance add
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
searxng/searx-instances#941 · 1 comentario ·
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 92/100
FluidNumerics/fluid-walk-blocker#89 ·
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
Los mantenedores suelen responder en 1 día