0
# Programmatic API
1
2
Simple API functions for integrating mypy into Python applications. These functions provide programmatic access to mypy's type checking functionality without requiring subprocess calls.
3
4
## Capabilities
5
6
### Basic Type Checking
7
8
Run mypy programmatically with the same interface as the command line tool.
9
10
```python { .api }
11
def run(args: list[str]) -> tuple[str, str, int]:
12
"""
13
Run mypy programmatically with command line arguments.
14
15
Parameters:
16
- args: list[str] - Command line arguments (same as mypy CLI)
17
18
Returns:
19
- tuple[str, str, int]: (stdout_output, stderr_output, exit_code)
20
- stdout_output: Normal type checking output and reports
21
- stderr_output: Error messages and warnings
22
- exit_code: 0 for success, non-zero for errors
23
24
Usage:
25
result = api.run(['--strict', 'myfile.py'])
26
"""
27
```
28
29
#### Usage Example
30
31
```python
32
from mypy import api
33
34
# Type check a single file
35
result = api.run(['myfile.py'])
36
stdout, stderr, exit_code = result
37
38
if exit_code == 0:
39
print("Type checking passed!")
40
if stdout:
41
print("Output:", stdout)
42
else:
43
print("Type checking failed!")
44
if stderr:
45
print("Errors:", stderr)
46
47
# Type check with options
48
result = api.run([
49
'--strict',
50
'--show-error-codes',
51
'--python-version', '3.11',
52
'src/'
53
])
54
55
# Type check multiple files
56
result = api.run(['file1.py', 'file2.py', 'package/'])
57
```
58
59
### Daemon Mode Type Checking
60
61
Run the dmypy daemon client programmatically for faster incremental type checking.
62
63
```python { .api }
64
def run_dmypy(args: list[str]) -> tuple[str, str, int]:
65
"""
66
Run dmypy daemon client programmatically.
67
68
Parameters:
69
- args: list[str] - Command line arguments for dmypy
70
71
Returns:
72
- tuple[str, str, int]: (stdout_output, stderr_output, exit_code)
73
74
Note:
75
- Not thread-safe, modifies sys.stdout and sys.stderr during execution
76
- Requires dmypy daemon to be running (start with: dmypy daemon)
77
78
Usage:
79
result = api.run_dmypy(['check', 'myfile.py'])
80
"""
81
```
82
83
#### Usage Example
84
85
```python
86
from mypy import api
87
88
# Start daemon first (usually done separately):
89
# subprocess.run(['dmypy', 'daemon'])
90
91
# Use daemon for faster checking
92
result = api.run_dmypy(['check', 'myfile.py'])
93
stdout, stderr, exit_code = result
94
95
# Daemon supports incremental checking
96
result = api.run_dmypy(['check', '--verbose', 'src/'])
97
98
# Stop daemon when done
99
result = api.run_dmypy(['stop'])
100
```
101
102
## Integration Patterns
103
104
### CI/CD Integration
105
106
```python
107
from mypy import api
108
import sys
109
110
def type_check_project():
111
"""Type check project in CI/CD pipeline."""
112
result = api.run([
113
'--strict',
114
'--show-error-codes',
115
'--junit-xml', 'mypy-results.xml',
116
'src/'
117
])
118
119
stdout, stderr, exit_code = result
120
121
if exit_code != 0:
122
print("Type checking failed:")
123
print(stderr)
124
sys.exit(1)
125
126
print("Type checking passed!")
127
return True
128
129
if __name__ == "__main__":
130
type_check_project()
131
```
132
133
### Development Tools Integration
134
135
```python
136
from mypy import api
137
import os
138
139
class TypeChecker:
140
"""Wrapper for mypy integration in development tools."""
141
142
def __init__(self, strict=True, python_version="3.11"):
143
self.strict = strict
144
self.python_version = python_version
145
146
def check_file(self, filepath):
147
"""Check a single file."""
148
args = []
149
150
if self.strict:
151
args.append('--strict')
152
153
args.extend(['--python-version', self.python_version])
154
args.append(filepath)
155
156
return api.run(args)
157
158
def check_files(self, filepaths):
159
"""Check multiple files."""
160
args = []
161
162
if self.strict:
163
args.append('--strict')
164
165
args.extend(['--python-version', self.python_version])
166
args.extend(filepaths)
167
168
return api.run(args)
169
170
def has_errors(self, result):
171
"""Check if result has type errors."""
172
stdout, stderr, exit_code = result
173
return exit_code != 0
174
175
# Usage
176
checker = TypeChecker(strict=True)
177
result = checker.check_file('mymodule.py')
178
179
if checker.has_errors(result):
180
print("Type errors found!")
181
```
182
183
### IDE/Editor Integration
184
185
```python
186
from mypy import api
187
import tempfile
188
import os
189
190
def check_code_snippet(code, filename="<string>"):
191
"""Type check a code snippet from an editor."""
192
# Write code to temporary file
193
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
194
f.write(code)
195
temp_path = f.name
196
197
try:
198
# Run mypy on the temporary file
199
result = api.run(['--show-error-codes', temp_path])
200
stdout, stderr, exit_code = result
201
202
# Parse errors and convert file paths back to original filename
203
if stderr:
204
stderr = stderr.replace(temp_path, filename)
205
206
return stdout, stderr, exit_code
207
finally:
208
# Clean up temporary file
209
os.unlink(temp_path)
210
211
# Usage in editor plugin
212
code = '''
213
def greet(name: str) -> str:
214
return f"Hello, {name}!"
215
216
# This will cause a type error
217
result = greet(42)
218
'''
219
220
stdout, stderr, exit_code = check_code_snippet(code, "editor_buffer.py")
221
if exit_code != 0:
222
print("Type errors in code:")
223
print(stderr)
224
```
225
226
## Error Handling
227
228
### Common Return Codes
229
230
- **0**: No errors found
231
- **1**: Type errors found
232
- **2**: Mypy crashed or invalid arguments
233
234
### Parsing Output
235
236
```python
237
from mypy import api
238
import re
239
240
def parse_mypy_output(result):
241
"""Parse mypy output into structured format."""
242
stdout, stderr, exit_code = result
243
244
errors = []
245
if stderr:
246
# Parse error lines: filename:line:column: error: message [error-code]
247
error_pattern = r'([^:]+):(\d+):(\d+): (error|warning|note): (.+?)(?:\s+\[([^\]]+)\])?$'
248
249
for line in stderr.strip().split('\n'):
250
match = re.match(error_pattern, line)
251
if match:
252
filename, line_num, col_num, level, message, error_code = match.groups()
253
errors.append({
254
'file': filename,
255
'line': int(line_num),
256
'column': int(col_num),
257
'level': level,
258
'message': message,
259
'error_code': error_code
260
})
261
262
return {
263
'exit_code': exit_code,
264
'stdout': stdout,
265
'stderr': stderr,
266
'errors': errors
267
}
268
269
# Usage
270
result = api.run(['myfile.py'])
271
parsed = parse_mypy_output(result)
272
273
for error in parsed['errors']:
274
print(f"{error['file']}:{error['line']}: {error['message']}")
275
```
276
277
## Performance Considerations
278
279
### Single vs Multiple Files
280
281
```python
282
# Less efficient - multiple mypy invocations
283
for file in files:
284
result = api.run([file])
285
286
# More efficient - single mypy invocation
287
result = api.run(files)
288
```
289
290
### Daemon Mode for Repeated Checks
291
292
```python
293
# For repeated type checking, use daemon mode
294
result = api.run_dmypy(['check'] + files) # Much faster for large projects
295
```
296
297
### Configuration via Files
298
299
```python
300
# Use mypy.ini or pyproject.toml for configuration instead of command line args
301
result = api.run(['src/']) # Configuration loaded from files
302
```