0
# Git Hooks
1
2
The numpydoc hooks module provides pre-commit integration for automated docstring validation. It enables project-wide enforcement of docstring quality standards through Git hooks and continuous integration workflows.
3
4
## Core Hook Functionality
5
6
### Main Hook Function
7
8
```python { .api }
9
def run_hook(files, config=None, ignore=None):
10
"""
11
Main hook function for pre-commit validation.
12
13
Processes a list of Python files for docstring validation,
14
using AST parsing to extract and validate docstrings from
15
functions, classes, and methods.
16
17
Parameters
18
----------
19
files : list of str
20
List of file paths to validate
21
config : dict, optional
22
Configuration dictionary with validation settings
23
If None, attempts to load from project configuration files
24
ignore : set of str, optional
25
Set of validation error codes to ignore
26
27
Returns
28
-------
29
int
30
Exit code (0 for success, non-zero if validation errors found)
31
32
Examples
33
--------
34
>>> from numpydoc.hooks.validate_docstrings import run_hook
35
>>> exit_code = run_hook(['src/mymodule.py'])
36
>>> print(f"Validation result: {exit_code}")
37
"""
38
```
39
40
### Configuration Parsing
41
42
```python { .api }
43
def parse_config(dir_path=None):
44
"""
45
Parse validation config from pyproject.toml/setup.cfg.
46
47
Searches for numpydoc validation configuration in standard
48
Python project configuration files, with pyproject.toml
49
taking precedence over setup.cfg.
50
51
Parameters
52
----------
53
dir_path : str, optional
54
Directory to search for config files
55
If None, uses current working directory
56
57
Returns
58
-------
59
dict
60
Configuration dictionary with keys:
61
- 'checks': set of validation check codes to apply
62
- 'ignore': set of error codes to ignore
63
- 'exclude': set of file patterns to exclude
64
- 'override': dict mapping object patterns to rule overrides
65
66
Examples
67
--------
68
>>> config = parse_config()
69
>>> print(config['checks'])
70
{'all', 'GL08'}
71
>>> print(config['exclude'])
72
{'tests/.*', '.*/_private.py'}
73
"""
74
```
75
76
### File Processing
77
78
```python { .api }
79
def process_file(filepath: str, config: dict):
80
"""
81
Process single file for validation.
82
83
Uses AST parsing to extract docstrings from Python source
84
code and validates them according to the provided configuration.
85
Handles syntax errors gracefully and reports validation issues.
86
87
Parameters
88
----------
89
filepath : str
90
Path to Python file to process
91
config : dict
92
Configuration dictionary with validation settings
93
94
Returns
95
-------
96
list of tuple
97
List of (line_number, error_code, message) validation errors
98
99
Examples
100
--------
101
>>> config = {'checks': {'all'}, 'ignore': set()}
102
>>> errors = process_file('src/mymodule.py', config)
103
>>> for line, code, msg in errors:
104
... print(f"{line}: {code}: {msg}")
105
"""
106
```
107
108
## AST-Based Validation
109
110
### AST Validator
111
112
```python { .api }
113
class AstValidator(validate.Validator):
114
"""
115
AST-based validator extending base Validator class.
116
117
Specialized validator that works with AST nodes to validate
118
docstrings extracted from Python source code. Handles the
119
relationship between AST nodes and their docstring content.
120
121
Parameters
122
----------
123
node : ast.AST
124
AST node (FunctionDef, ClassDef, etc.) to validate
125
obj_name : str
126
Qualified name of the object
127
**kwargs
128
Additional validation configuration options
129
130
Attributes
131
----------
132
node : ast.AST
133
The AST node being validated
134
obj_name : str
135
Qualified object name for error reporting
136
"""
137
```
138
139
### AST Visitor
140
141
```python { .api }
142
class DocstringVisitor(ast.NodeVisitor):
143
"""
144
AST visitor for extracting docstrings from Python source.
145
146
Traverses the AST to find function and class definitions,
147
extracts their docstrings, and applies validation rules.
148
Handles nested classes and methods properly.
149
150
Parameters
151
----------
152
config : dict
153
Validation configuration
154
filepath : str
155
Path to file being processed (for error reporting)
156
157
Attributes
158
----------
159
config : dict
160
Validation configuration dictionary
161
filepath : str
162
Current file path
163
errors : list
164
Accumulated validation errors
165
"""
166
167
def visit_FunctionDef(self, node):
168
"""
169
Visit function definition nodes.
170
171
Extracts and validates docstrings from function definitions,
172
including methods within classes.
173
174
Parameters
175
----------
176
node : ast.FunctionDef
177
Function definition AST node
178
"""
179
180
def visit_ClassDef(self, node):
181
"""
182
Visit class definition nodes.
183
184
Extracts and validates docstrings from class definitions
185
and recursively processes methods within the class.
186
187
Parameters
188
----------
189
node : ast.ClassDef
190
Class definition AST node
191
"""
192
```
193
194
## Utility Functions
195
196
### Project Detection
197
198
```python { .api }
199
def find_project_root(srcs: List[str]) -> str:
200
"""
201
Find project root from config files.
202
203
Searches up the directory tree from the given source files
204
to find the project root, identified by configuration files
205
like pyproject.toml, setup.cfg, setup.py, or .git directory.
206
207
Parameters
208
----------
209
srcs : list of str
210
List of source file paths to start search from
211
212
Returns
213
-------
214
str
215
Path to project root directory
216
217
Examples
218
--------
219
>>> root = find_project_root(['src/mymodule.py'])
220
>>> print(root)
221
'/path/to/project'
222
"""
223
```
224
225
## Pre-commit Integration
226
227
### Hook Configuration
228
229
Add numpydoc validation to your `.pre-commit-config.yaml`:
230
231
```yaml
232
repos:
233
- repo: https://github.com/numpy/numpydoc
234
rev: v1.9.0
235
hooks:
236
- id: numpydoc-validation
237
files: \.py$
238
```
239
240
### Local Hook Setup
241
242
For local pre-commit hooks, use:
243
244
```yaml
245
repos:
246
- repo: local
247
hooks:
248
- id: numpydoc-validation
249
name: numpydoc docstring validation
250
entry: python -m numpydoc.hooks.validate_docstrings
251
language: system
252
files: \.py$
253
pass_filenames: true
254
```
255
256
## Configuration Examples
257
258
### pyproject.toml Configuration
259
260
```toml
261
[tool.numpydoc_validation]
262
checks = [
263
"all", # Enable all validation checks
264
"GL08", # Require docstrings
265
]
266
267
ignore = [
268
"GL01", # Allow docstring not starting immediately after quotes
269
"SS01", # Allow missing summary
270
]
271
272
exclude = [
273
"tests/.*", # Exclude test files
274
".*/_private.py", # Exclude private modules
275
"docs/conf.py", # Exclude Sphinx config
276
]
277
278
# Per-object validation overrides
279
[tool.numpydoc_validation.override]
280
"mypackage.legacy.*" = {all = false} # Disable all checks for legacy code
281
"mypackage.experimental.func" = {GL01 = false} # Disable specific check
282
```
283
284
### setup.cfg Configuration
285
286
```ini
287
[numpydoc_validation]
288
checks = all,GL08
289
ignore = GL01,SS01
290
exclude =
291
tests/.*
292
.*/_private.py
293
docs/conf.py
294
295
# Override format: object_pattern:error_code=false
296
override =
297
mypackage.legacy.*:all=false
298
mypackage.experimental.func:GL01=false
299
```
300
301
## Command-Line Usage
302
303
### Direct Hook Execution
304
305
```bash
306
# Run validation hook on specific files
307
python -m numpydoc.hooks.validate_docstrings src/mymodule.py src/utils.py
308
309
# Run with configuration file
310
python -m numpydoc.hooks.validate_docstrings --config pyproject.toml src/*.py
311
312
# Run with specific validation checks
313
python -m numpydoc.hooks.validate_docstrings --checks GL01,SS01 src/
314
```
315
316
### Pre-commit Integration
317
318
```bash
319
# Install pre-commit hooks
320
pre-commit install
321
322
# Run hooks manually
323
pre-commit run numpydoc-validation
324
325
# Run on all files
326
pre-commit run numpydoc-validation --all-files
327
328
# Run with verbose output
329
pre-commit run numpydoc-validation --verbose
330
```
331
332
## Usage Examples
333
334
### Basic Hook Usage
335
336
```python
337
from numpydoc.hooks.validate_docstrings import run_hook, parse_config
338
339
# Load project configuration
340
config = parse_config()
341
342
# Run validation on changed files
343
files = ['src/module1.py', 'src/module2.py']
344
exit_code = run_hook(files, config=config)
345
346
if exit_code == 0:
347
print("All docstrings valid!")
348
else:
349
print("Validation errors found")
350
```
351
352
### Custom Configuration
353
354
```python
355
from numpydoc.hooks.validate_docstrings import run_hook
356
357
# Custom validation configuration
358
config = {
359
'checks': {'GL01', 'SS01', 'PR01'},
360
'ignore': {'GL08'},
361
'exclude': {'tests/.*'},
362
'override': {
363
'mymodule.legacy_func': {'all': False}
364
}
365
}
366
367
# Run with custom config
368
exit_code = run_hook(['src/mymodule.py'], config=config)
369
```
370
371
### AST Processing Example
372
373
```python
374
import ast
375
from numpydoc.hooks.validate_docstrings import DocstringVisitor
376
377
# Parse Python source
378
with open('src/mymodule.py', 'r') as f:
379
source = f.read()
380
381
tree = ast.parse(source)
382
383
# Extract and validate docstrings
384
config = {'checks': {'all'}, 'ignore': set()}
385
visitor = DocstringVisitor(config, 'src/mymodule.py')
386
visitor.visit(tree)
387
388
# Print validation errors
389
for error in visitor.errors:
390
print(f"Line {error[0]}: {error[1]}: {error[2]}")
391
```
392
393
### Integration with CI/CD
394
395
```yaml
396
# GitHub Actions workflow
397
name: Docstring Validation
398
on: [push, pull_request]
399
400
jobs:
401
validate-docstrings:
402
runs-on: ubuntu-latest
403
steps:
404
- uses: actions/checkout@v2
405
- name: Set up Python
406
uses: actions/setup-python@v2
407
with:
408
python-version: '3.9'
409
- name: Install dependencies
410
run: |
411
pip install numpydoc
412
- name: Validate docstrings
413
run: |
414
python -m numpydoc.hooks.validate_docstrings src/
415
```
416
417
## Error Handling
418
419
The hooks module provides comprehensive error handling:
420
421
- **Syntax Errors**: Files with syntax errors are skipped with warnings
422
- **Import Errors**: Missing dependencies are handled gracefully
423
- **Configuration Errors**: Invalid config files produce clear error messages
424
- **File Access**: Permission and file system errors are reported appropriately
425
426
Exit codes follow standard conventions:
427
- **0**: Success (no validation errors)
428
- **1**: Validation errors found
429
- **2**: Configuration or argument errors
430
- **3**: File access or parsing errors