0
# Core Formatting
1
2
Main docstring formatting functionality providing the primary interface for processing Python files and docstrings according to PEP 257 conventions.
3
4
## Capabilities
5
6
### Formatter Class
7
8
The main class responsible for docstring formatting operations, handling file processing, source code parsing, and docstring transformation.
9
10
```python { .api }
11
class Formatter:
12
"""Format docstrings in Python source files."""
13
14
# Quote type constants
15
STR_QUOTE_TYPES = ('"""', "'''")
16
RAW_QUOTE_TYPES = ('r"""', 'R"""', "r'''", "R'''")
17
UCODE_QUOTE_TYPES = ('u"""', 'U"""', "u'''", "U'''")
18
QUOTE_TYPES = STR_QUOTE_TYPES + RAW_QUOTE_TYPES + UCODE_QUOTE_TYPES
19
20
def __init__(self, args, stderror, stdin, stdout):
21
"""
22
Initialize formatter with configuration and I/O streams.
23
24
Args:
25
args: Parsed configuration arguments from Configurater
26
stderror: Standard error stream for error output
27
stdin: Standard input stream for reading from stdin
28
stdout: Standard output stream for formatted output
29
"""
30
31
def do_format_files(self) -> int:
32
"""
33
Format all files specified in configuration.
34
35
Returns:
36
int: Exit code (FormatResult constant)
37
"""
38
39
def do_format_standard_in(self, parser) -> None:
40
"""
41
Format docstrings from standard input.
42
43
Args:
44
parser: ArgumentParser instance for error handling
45
"""
46
```
47
48
#### File Processing Methods
49
50
```python { .api }
51
def _do_format_file(self, filename):
52
"""
53
Format docstrings in a single file.
54
55
Args:
56
filename (str): Path to Python file to format
57
58
Returns:
59
Formatted source code or None if unchanged
60
"""
61
62
def _do_format_code(self, source):
63
"""
64
Format docstrings in source code string.
65
66
Args:
67
source (str): Python source code to format
68
69
Returns:
70
str: Formatted source code
71
"""
72
```
73
74
#### Core Formatting Logic
75
76
```python { .api }
77
def _format_code(self, source, summary_wrap_length, description_wrap_length,
78
make_summary_multi_line, force_wrap, tab_width, blank,
79
pre_summary_newline, pre_summary_space, close_quotes_on_newline,
80
style):
81
"""
82
Apply formatting rules to source code.
83
84
Args:
85
source (str): Python source code
86
summary_wrap_length (int): Maximum line length for summary
87
description_wrap_length (int): Maximum line length for description
88
make_summary_multi_line (bool): Convert single-line to multi-line docstrings
89
force_wrap (bool): Force wrapping even if it creates messy formatting
90
tab_width (int): Tab width for indentation calculations
91
blank (bool): Add blank line after description
92
pre_summary_newline (bool): Add newline before summary
93
pre_summary_space (bool): Add space after opening quotes
94
close_quotes_on_newline (bool): Place closing quotes on new line
95
style (str): Docstring style ('sphinx' or 'epytext')
96
97
Returns:
98
str: Formatted source code
99
"""
100
```
101
102
#### Docstring Processing Methods
103
104
```python { .api }
105
def _do_format_docstring(self, docstring, summary_wrap_length, description_wrap_length,
106
make_summary_multi_line, force_wrap, tab_width, blank,
107
pre_summary_newline, pre_summary_space, close_quotes_on_newline,
108
style):
109
"""
110
Format individual docstring according to PEP 257.
111
112
Args:
113
docstring (str): Raw docstring content
114
summary_wrap_length (int): Summary line length limit
115
description_wrap_length (int): Description line length limit
116
make_summary_multi_line (bool): Multi-line summary conversion
117
force_wrap (bool): Force wrapping mode
118
tab_width (int): Tab character width
119
blank (bool): Add blank line after description
120
pre_summary_newline (bool): Newline before summary
121
pre_summary_space (bool): Space after opening quotes
122
close_quotes_on_newline (bool): Closing quote placement
123
style (str): Field list style ('sphinx' or 'epytext')
124
125
Returns:
126
str: Formatted docstring
127
"""
128
129
def _do_format_oneline_docstring(self, contents, summary_wrap_length, force_wrap,
130
tab_width, make_summary_multi_line,
131
close_quotes_on_newline):
132
"""
133
Format single-line docstrings.
134
135
Args:
136
contents (str): Docstring content
137
summary_wrap_length (int): Line length limit
138
force_wrap (bool): Force wrapping mode
139
tab_width (int): Tab width for calculations
140
make_summary_multi_line (bool): Convert to multi-line
141
close_quotes_on_newline (bool): Quote placement
142
143
Returns:
144
str: Formatted single-line docstring
145
"""
146
147
def _do_format_multiline_docstring(self, contents, summary_wrap_length,
148
description_wrap_length, force_wrap, tab_width,
149
blank, pre_summary_newline, pre_summary_space,
150
close_quotes_on_newline, style):
151
"""
152
Format multi-line docstrings.
153
154
Args:
155
contents (str): Docstring content
156
summary_wrap_length (int): Summary line length limit
157
description_wrap_length (int): Description line length limit
158
force_wrap (bool): Force wrapping mode
159
tab_width (int): Tab character width
160
blank (bool): Add blank line after description
161
pre_summary_newline (bool): Newline before summary
162
pre_summary_space (bool): Space after opening quotes
163
close_quotes_on_newline (bool): Closing quote placement
164
style (str): Field list style
165
166
Returns:
167
str: Formatted multi-line docstring
168
"""
169
170
def _do_strip_docstring(self, docstring):
171
"""
172
Strip and normalize docstring quotes and whitespace.
173
174
Args:
175
docstring (str): Raw docstring with quotes
176
177
Returns:
178
tuple: (stripped_content, indentation)
179
"""
180
```
181
182
### FormatResult Class
183
184
Exit code constants for formatter operations.
185
186
```python { .api }
187
class FormatResult:
188
"""Exit codes for docformatter operations."""
189
190
ok = 0 # Successful completion
191
error = 1 # Error occurred during processing
192
interrupted = 2 # Operation interrupted by user (Ctrl+C)
193
check_failed = 3 # Check mode found formatting issues
194
```
195
196
## Usage Examples
197
198
### Basic File Formatting
199
200
```python
201
import sys
202
from docformatter import Formatter, Configurater, FormatResult
203
204
# Setup configuration
205
args = ['--in-place', 'example.py']
206
configurator = Configurater(args)
207
configurator.do_parse_arguments()
208
209
# Create formatter
210
formatter = Formatter(
211
configurator.args,
212
stderror=sys.stderr,
213
stdin=sys.stdin,
214
stdout=sys.stdout
215
)
216
217
# Format files
218
result = formatter.do_format_files()
219
220
if result == FormatResult.ok:
221
print("Formatting completed successfully")
222
elif result == FormatResult.error:
223
print("Error occurred during formatting")
224
elif result == FormatResult.check_failed:
225
print("Files need formatting")
226
```
227
228
### Formatting with Custom Configuration
229
230
```python
231
import sys
232
from docformatter import Formatter, Configurater
233
234
# Setup with Black compatibility and custom wrap lengths
235
args = [
236
'--black',
237
'--wrap-summaries', '88',
238
'--wrap-descriptions', '88',
239
'--in-place',
240
'src/'
241
]
242
243
configurator = Configurater(args)
244
configurator.do_parse_arguments()
245
246
formatter = Formatter(
247
configurator.args,
248
stderror=sys.stderr,
249
stdin=sys.stdin,
250
stdout=sys.stdout
251
)
252
253
# Format with custom settings
254
result = formatter.do_format_files()
255
```
256
257
### Check Mode for CI/CD
258
259
```python
260
import sys
261
from docformatter import Formatter, Configurater, FormatResult
262
263
# Check formatting without making changes
264
args = ['--check', '--diff', '--recursive', '.']
265
configurator = Configurater(args)
266
configurator.do_parse_arguments()
267
268
formatter = Formatter(
269
configurator.args,
270
stderror=sys.stderr,
271
stdin=sys.stdin,
272
stdout=sys.stdout
273
)
274
275
result = formatter.do_format_files()
276
277
# Exit with appropriate code for CI/CD
278
sys.exit(result)
279
```
280
281
### Standard Input Processing
282
283
```python
284
import sys
285
from docformatter import Formatter, Configurater
286
287
# Process from stdin
288
args = ['-'] # '-' indicates stdin input
289
configurator = Configurater(args)
290
configurator.do_parse_arguments()
291
292
formatter = Formatter(
293
configurator.args,
294
stderror=sys.stderr,
295
stdin=sys.stdin,
296
stdout=sys.stdout
297
)
298
299
# Format from stdin and output to stdout
300
formatter.do_format_standard_in(configurator.parser)
301
```
302
303
## Formatting Rules Applied
304
305
The Formatter applies the following PEP 257 rules:
306
307
1. **Triple Quote Consistency**: Uses triple double quotes for all docstrings
308
2. **Single-line Format**: Keeps simple docstrings on one line when possible
309
3. **Multi-line Format**: Summary line + blank line + description for complex docstrings
310
4. **Closing Quote Placement**: Places closing quotes appropriately based on content
311
5. **Indentation**: Maintains proper indentation relative to the containing code
312
6. **Whitespace**: Removes trailing whitespace and normalizes internal spacing
313
7. **Summary Capitalization**: Capitalizes first word unless in non-cap list
314
8. **Summary Punctuation**: Adds period to summary if missing
315
9. **Field List Formatting**: Preserves and formats Sphinx/Epytext field lists
316
10. **Code Block Preservation**: Maintains literal blocks and code examples
317
318
## Error Handling
319
320
The Formatter handles various error conditions:
321
322
- **Syntax Errors**: Skips files with invalid Python syntax
323
- **Encoding Issues**: Uses Encoder class for robust file reading
324
- **File Access**: Reports permission and file not found errors
325
- **Tokenization Errors**: Gracefully handles tokenization failures
326
- **Keyboard Interrupts**: Returns interrupted exit code for clean shutdown