Automatically add trailing commas to calls and literals in Python code
npx @tessl/cli install tessl/pypi-add-trailing-comma@3.2.00
# add-trailing-comma
1
2
A Python tool and pre-commit hook that automatically adds trailing commas to function calls, literals (lists, tuples, dicts, sets), function definitions, import statements, class definitions, with statements, match statements, and PEP-695 type aliases. This improves code maintainability by ensuring consistent trailing comma usage, reducing git diff noise, preserving git blame information, and avoiding arbitrary indentation issues.
3
4
## Package Information
5
6
- **Package Name**: add-trailing-comma (for pip), add_trailing_comma (Python module)
7
- **Language**: Python
8
- **Installation**: `pip install add-trailing-comma`
9
- **Python Requirements**: >=3.9
10
- **Dependencies**: tokenize-rt>=3.0.1
11
12
## Core Imports
13
14
This package is primarily designed for command-line usage and does not export a public programmatic API. The `__init__.py` is empty, making direct imports unsuitable for typical programmatic use.
15
16
**Command-line usage** (recommended):
17
```bash
18
add-trailing-comma
19
```
20
21
**Python module invocation**:
22
```bash
23
python -m add_trailing_comma
24
```
25
26
**Internal API access** (for advanced use cases, accessing private modules):
27
```python
28
from add_trailing_comma._main import main, fix_file
29
```
30
31
## Basic Usage
32
33
### Command Line Usage
34
35
```bash
36
# Process single file
37
add-trailing-comma script.py
38
39
# Process multiple files
40
add-trailing-comma file1.py file2.py src/
41
42
# Read from stdin
43
cat script.py | add-trailing-comma -
44
45
# Exit with 0 even if files were changed (useful for CI)
46
add-trailing-comma --exit-zero-even-if-changed file.py
47
```
48
49
### Pre-commit Hook Usage
50
51
Add to your `.pre-commit-config.yaml`:
52
53
```yaml
54
- repo: https://github.com/asottile/add-trailing-comma
55
rev: v3.2.0
56
hooks:
57
- id: add-trailing-comma
58
```
59
60
### Programmatic Usage
61
62
**Note**: The following shows internal API usage accessing private modules. This is not recommended for production use as private APIs may change without notice.
63
64
```python
65
import argparse
66
from add_trailing_comma._main import fix_file, main
67
68
# Process a single file using internal API
69
args = argparse.Namespace(exit_zero_even_if_changed=False)
70
result = fix_file("script.py", args)
71
72
# Use main function with arguments
73
result = main(["script.py", "--exit-zero-even-if-changed"])
74
```
75
76
## Capabilities
77
78
### Command Line Interface
79
80
The main entry point for command-line usage with argument parsing and file processing.
81
82
```python { .api }
83
def main(argv: Sequence[str] | None = None) -> int:
84
"""
85
Main entry point for command line interface.
86
87
Parameters:
88
- argv: Command line arguments (defaults to sys.argv if None)
89
90
Returns:
91
int: Exit code (0 for success or no changes, 1 for errors or changes made)
92
93
Available command line options:
94
- filenames: List of files to process
95
- --exit-zero-even-if-changed: Exit with 0 even if files were modified
96
- --py35-plus, --py36-plus: Legacy flags (deprecated, no effect)
97
"""
98
```
99
100
### File Processing
101
102
Process individual files to add trailing commas with configurable options.
103
104
```python { .api }
105
def fix_file(filename: str, args: argparse.Namespace) -> int:
106
"""
107
Process a single file to add trailing commas.
108
109
Parameters:
110
- filename: Path to file to process, or '-' for stdin
111
- args: Namespace with configuration options (requires exit_zero_even_if_changed attribute)
112
113
Returns:
114
int: 1 if file was changed or error occurred, 0 if no changes or exit_zero_even_if_changed=True
115
116
Handles:
117
- Unicode decode errors (prints error message, returns 1)
118
- Syntax errors (returns content unchanged)
119
- File I/O operations for both files and stdin
120
"""
121
```
122
123
### Source Code Transformation
124
125
Core internal functionality for transforming Python source code to add trailing commas. This is a private function used internally by the tool.
126
127
```python { .api }
128
def _fix_src(contents_text: str) -> str:
129
"""
130
Internal function that applies AST transformations to add trailing commas.
131
132
Note: This is a private function (prefix '_') and should not be used in
133
production code as it may change without notice.
134
135
Parameters:
136
- contents_text: Python source code as string
137
138
Returns:
139
str: Transformed source code with trailing commas added
140
141
Raises:
142
SyntaxError: Returns original content if syntax errors are encountered
143
"""
144
```
145
146
## Transformations Supported
147
148
### Function Calls
149
150
Adds trailing commas to multi-line function calls:
151
152
```python
153
# Before
154
function_call(
155
argument,
156
5 ** 5,
157
kwarg=foo
158
)
159
160
# After
161
function_call(
162
argument,
163
5 ** 5,
164
kwarg=foo,
165
)
166
```
167
168
### Literals
169
170
Adds trailing commas to lists, tuples, dictionaries, and sets:
171
172
```python
173
# Lists
174
x = [
175
1, 2, 3, # trailing comma added
176
]
177
178
# Tuples
179
y = (
180
'a', 'b', 'c', # trailing comma added
181
)
182
183
# Dictionaries
184
config = {
185
'key1': 'value1',
186
'key2': 'value2', # trailing comma added
187
}
188
189
# Sets
190
items = {
191
'item1',
192
'item2', # trailing comma added
193
}
194
```
195
196
### Function Definitions
197
198
Adds trailing commas to function and method parameters:
199
200
```python
201
def func(
202
arg1,
203
arg2, # trailing comma added
204
):
205
pass
206
207
async def async_func(
208
arg1,
209
arg2, # trailing comma added
210
):
211
pass
212
```
213
214
### Import Statements
215
216
Adds trailing commas to from-import statements:
217
218
```python
219
from os import (
220
path,
221
makedirs, # trailing comma added
222
)
223
```
224
225
### Class Definitions
226
227
Adds trailing commas to class inheritance lists:
228
229
```python
230
class MyClass(
231
Base1,
232
Base2, # trailing comma added
233
):
234
pass
235
```
236
237
### With Statements
238
239
Adds trailing commas to with statement context managers:
240
241
```python
242
with (
243
open('f1', 'r') as f1,
244
open('f2', 'w') as f2, # trailing comma added
245
):
246
pass
247
```
248
249
### Match Statements (Python 3.10+)
250
251
Adds trailing commas to match patterns:
252
253
```python
254
match x:
255
case A(
256
1,
257
2, # trailing comma added
258
):
259
pass
260
case (
261
1,
262
2, # trailing comma added
263
):
264
pass
265
case [
266
1,
267
2, # trailing comma added
268
]:
269
pass
270
case {
271
'x': 1,
272
'y': 2, # trailing comma added
273
}:
274
pass
275
```
276
277
### PEP-695 Type Aliases (Python 3.12+)
278
279
Adds trailing commas to type parameter lists:
280
281
```python
282
def f[
283
T, # trailing comma added
284
](x: T) -> T:
285
return x
286
287
class A[
288
K, # trailing comma added
289
]:
290
def __init__(self, x: K) -> None:
291
self.x = x
292
293
type ListOrSet[
294
T, # trailing comma added
295
] = list[T] | set[T]
296
```
297
298
## Additional Features
299
300
### Parentheses Formatting
301
302
The tool also performs "unhugging" - formatting parentheses positioning:
303
304
```python
305
# Unhug trailing paren
306
x(
307
arg1,
308
arg2, # trailing comma and proper closing
309
)
310
311
# Unhug leading paren
312
function_name(
313
arg1,
314
arg2,
315
)
316
317
# Match closing brace indentation
318
x = [
319
1,
320
2,
321
3,
322
] # proper indentation
323
```
324
325
### Comma Removal
326
327
Removes unnecessary commas from single-line structures:
328
329
```python
330
# Before
331
[1, 2, 3,]
332
[1, 2, 3, ]
333
334
# After
335
[1, 2, 3]
336
[1, 2, 3]
337
```
338
339
## Command Line Arguments
340
341
The tool supports the following command line arguments:
342
343
- **filenames**: List of files to process (accepts multiple files and directories)
344
- **--exit-zero-even-if-changed**: Exit with code 0 even if files were modified
345
- **--py35-plus**: Legacy flag (deprecated, does nothing)
346
- **--py36-plus**: Legacy flag (deprecated, does nothing)
347
348
## Error Handling
349
350
The tool handles various error conditions gracefully:
351
352
- **Syntax Errors**: Files with syntax errors are returned unchanged
353
- **Unicode Errors**: Non-UTF-8 files are skipped with error message
354
- **File Access**: Handles stdin input with '-' filename
355
356
## Integration
357
358
### Pre-commit Hook
359
360
The tool is designed to work seamlessly with pre-commit hooks for automated code formatting in development workflows.
361
362
### CI/CD Integration
363
364
Use `--exit-zero-even-if-changed` flag in CI environments where you want the tool to run but not fail the build when changes are made.
365
366
## Dependencies and Types
367
368
The tool relies on the following dependencies and type definitions:
369
370
### External Dependencies
371
372
```python { .api }
373
# Required external dependency
374
from tokenize_rt import src_to_tokens, tokens_to_src, Token, Offset
375
376
# Standard library dependencies
377
from typing import Sequence, Iterable
378
from collections.abc import Sequence
379
from argparse import Namespace, ArgumentParser
380
import ast
381
import sys
382
```
383
384
### Core Type Signatures
385
386
```python { .api }
387
# Main API functions
388
def main(argv: Sequence[str] | None = None) -> int
389
def fix_file(filename: str, args: Namespace) -> int
390
391
# Internal transformation function
392
def _fix_src(contents_text: str) -> str
393
394
# Helper types from tokenize-rt
395
Token: # Represents a token with .src, .name, .offset attributes
396
Offset: # Represents position in source (line, column)
397
```