docformatter 1.7.8 treats a triple-quoted string that opens a parenthesized concatenation as a docstring and reformats its contents: it splits the first sentence off, indents the remainder by four spaces, and moves the closing quotes onto their own line. The file still compiles, so the only effect is that the string the program builds is wrong.
Reproducer
X = (
"""#!/bin/bash
# Ends here.
# A second line.
_real="""
+ "y"
)
$ docformatter --in-place t.py
$ python3 -c "ns={}; exec(open('t.py').read(), ns); print(repr(ns['X']))"
| version |
value of X |
| 1.7.7 |
'#!/bin/bash\n# Ends here.\n# A second line.\n_real=y' |
| 1.7.8 |
'#!/bin/bash\n# Ends here.\n\n # A second line.\n _real=\n y' |
No config file and no flags are needed. The trigger is the string's position: the same literal assigned directly to a name is left alone.
# Ends here. matters because the trailing period is what makes docformatter treat the first line as a summary and split a description off after it.
Scale
Running 1.7.7 and 1.7.8 over the same 1,257-file tree, one file at a time, on CPython 3.11: of the 1,250 files both versions processed without error, 475 come out different. Most are docstring-formatting changes that look intentional, but this class is in there and is invisible: the output parses, so nothing downstream complains.
Root cause
git bisect between v1.7.7 and 1b3f03d names 926d9f0 ("refactor: split long functions into smaller functions", #318) as the first bad commit. Its parent fe1a85f is clean. Being a refactor, the behavior change looks unintended.
This is the same family as #344 (non-docstring literals in call arguments), but a different position: a parenthesized concatenation rather than a call argument, so #364 does not cover it. The reproducer above works as a test case.
Environment
CPython 3.11.15, Linux x86-64, docformatter==1.7.8 from PyPI. Still present on master.
docformatter 1.7.8 treats a triple-quoted string that opens a parenthesized concatenation as a docstring and reformats its contents: it splits the first sentence off, indents the remainder by four spaces, and moves the closing quotes onto their own line. The file still compiles, so the only effect is that the string the program builds is wrong.
Reproducer
X'#!/bin/bash\n# Ends here.\n# A second line.\n_real=y''#!/bin/bash\n# Ends here.\n\n # A second line.\n _real=\n y'No config file and no flags are needed. The trigger is the string's position: the same literal assigned directly to a name is left alone.
# Ends here.matters because the trailing period is what makes docformatter treat the first line as a summary and split a description off after it.Scale
Running 1.7.7 and 1.7.8 over the same 1,257-file tree, one file at a time, on CPython 3.11: of the 1,250 files both versions processed without error, 475 come out different. Most are docstring-formatting changes that look intentional, but this class is in there and is invisible: the output parses, so nothing downstream complains.
Root cause
git bisectbetween v1.7.7 and 1b3f03d names 926d9f0 ("refactor: split long functions into smaller functions", #318) as the first bad commit. Its parent fe1a85f is clean. Being a refactor, the behavior change looks unintended.This is the same family as #344 (non-docstring literals in call arguments), but a different position: a parenthesized concatenation rather than a call argument, so #364 does not cover it. The reproducer above works as a test case.
Environment
CPython 3.11.15, Linux x86-64,
docformatter==1.7.8from PyPI. Still present on master.