0
# AST Checker and Analysis Engine
1
2
Core checker functionality providing detailed AST analysis, scope management, and binding tracking. The Checker class is the heart of pyflakes, performing static analysis by parsing Python code into Abstract Syntax Trees and tracking variable usage across different scopes.
3
4
## Capabilities
5
6
### Main Checker Class
7
8
The primary analysis engine that processes AST nodes and manages scope hierarchies to detect various code issues.
9
10
```python { .api }
11
class Checker:
12
"""
13
Main AST checker for Python code analysis.
14
15
Attributes:
16
- nodeDepth: int, current AST traversal depth
17
- offset: tuple[int, int] | None, position offset for error reporting
18
- builtIns: set[str], built-in names to recognize
19
- deadScopes: list[Any], scopes that are no longer active
20
- messages: list[Any], collected analysis messages
21
- filename: str, name of file being analyzed
22
- withDoctest: bool, whether to analyze doctest blocks
23
- scopeStack: list[Scope], stack of active scopes
24
- exceptHandlers: list[Any], active exception handlers
25
- root: ast.AST, root AST node being analyzed
26
"""
27
28
def __init__(
29
self,
30
tree: ast.AST,
31
filename: str = ...,
32
builtins: Iterable[str] | None = ...,
33
withDoctest: bool = ...,
34
file_tokens: tuple[Any, ...] = ...,
35
) -> None:
36
"""
37
Initialize checker with AST tree and configuration.
38
39
Parameters:
40
- tree: ast.AST, parsed AST tree to analyze
41
- filename: str, filename for error reporting
42
- builtins: Iterable[str] | None, additional built-in names
43
- withDoctest: bool, analyze doctest blocks
44
- file_tokens: tuple[Any, ...], tokenized source for advanced analysis
45
"""
46
```
47
48
**Key Methods:**
49
50
```python { .api }
51
def report(self, messageClass: Callable[_P, Message], *args: _P.args, **kwargs: _P.kwargs) -> None: ...
52
def addBinding(self, node: ast.AST, value: Binding) -> None: ...
53
def handleChildren(self, tree: ast.AST, omit: _OmitType = ...) -> None: ...
54
def pushScope(self, scopeClass: type[Scope] = ...) -> None: ...
55
def popScope(self) -> None: ...
56
```
57
58
**Properties:**
59
60
```python { .api }
61
@property
62
def futuresAllowed(self) -> bool:
63
"""Whether __future__ imports are allowed at current position."""
64
65
@property
66
def annotationsFutureEnabled(self) -> bool:
67
"""Whether annotations __future__ import is active."""
68
69
@property
70
def scope(self) -> Scope:
71
"""Current active scope."""
72
```
73
74
### Scope and Binding Management
75
76
#### Binding Classes
77
78
Base classes for tracking name bindings and their usage throughout the code.
79
80
```python { .api }
81
class Binding:
82
"""
83
Base class for name bindings.
84
85
Attributes:
86
- name: str, the bound name
87
- source: ast.AST | None, AST node where binding occurs
88
- used: Literal[False] | tuple[Any, ast.AST], usage tracking
89
"""
90
91
def __init__(self, name: str, source: ast.AST | None) -> None: ...
92
def redefines(self, other: Binding) -> bool:
93
"""Check if this binding redefines another binding."""
94
95
class Definition(Binding):
96
"""Base class for name definitions."""
97
98
class Importation(Definition):
99
"""
100
Import statement binding.
101
102
Attributes:
103
- fullName: str, full module name
104
- redefined: list[Any], names redefined by this import
105
"""
106
107
def __init__(self, name: str, source: ast.AST | None, full_name: str | None = ...) -> None: ...
108
109
@property
110
def source_statement(self) -> str:
111
"""Source import statement text."""
112
```
113
114
#### Scope Classes
115
116
Different types of scopes for tracking variable visibility and lifetime.
117
118
```python { .api }
119
class Scope(dict[str, Binding]):
120
"""
121
Base scope class mapping names to bindings.
122
123
Attributes:
124
- importStarred: bool, whether scope has star imports
125
"""
126
127
class ModuleScope(Scope):
128
"""Module-level scope."""
129
130
class FunctionScope(Scope):
131
"""
132
Function scope with additional function-specific tracking.
133
134
Attributes:
135
- usesLocals: bool, whether function uses locals()
136
- globals: set[str], names declared global
137
- returnValue: Any, return value tracking
138
- isGenerator: bool, whether function is a generator
139
"""
140
141
def __init__(self) -> None: ...
142
def unusedAssignments(self) -> Iterator[tuple[str, Binding]]:
143
"""Iterate over unused assignments in this scope."""
144
145
class ClassScope(Scope):
146
"""Class scope."""
147
```
148
149
### Core Analysis Methods
150
151
Methods for managing the analysis process, scope handling, and message reporting.
152
153
```python { .api }
154
def report(self, messageClass: Callable[_P, Message], *args: _P.args, **kwargs: _P.kwargs) -> None:
155
"""
156
Report an analysis message.
157
158
Parameters:
159
- messageClass: Message class to instantiate
160
- args: Positional arguments for message
161
- kwargs: Keyword arguments for message
162
"""
163
164
def addBinding(self, node: ast.AST, value: Binding) -> None:
165
"""
166
Add a name binding to current scope.
167
168
Parameters:
169
- node: AST node where binding occurs
170
- value: Binding object representing the name
171
"""
172
173
def pushScope(self, scopeClass: type[Scope] = ...) -> None:
174
"""
175
Push new scope onto scope stack.
176
177
Parameters:
178
- scopeClass: Type of scope to create
179
"""
180
181
def popScope(self) -> None:
182
"""Pop current scope from scope stack."""
183
```
184
185
### Deferred Processing
186
187
Methods for handling analysis that must be delayed until after initial AST traversal.
188
189
```python { .api }
190
def deferFunction(self, callable: _AnyFunction) -> None:
191
"""
192
Defer function analysis until after initial pass.
193
194
Parameters:
195
- callable: Function to call during deferred processing
196
"""
197
198
def deferAssignment(self, callable: _AnyFunction) -> None:
199
"""
200
Defer assignment analysis for complex cases.
201
202
Parameters:
203
- callable: Function to call during deferred processing
204
"""
205
206
def runDeferred(self, deferred: _AnyFunction) -> None:
207
"""
208
Execute deferred analysis function.
209
210
Parameters:
211
- deferred: Previously deferred function to execute
212
"""
213
```
214
215
### Scope and Binding Management
216
217
#### Binding Classes
218
219
Base classes for tracking name bindings and their usage throughout the code.
220
221
```python { .api }
222
class Binding:
223
"""
224
Base class for name bindings.
225
226
Attributes:
227
- name: str, the bound name
228
- source: ast.AST | None, AST node where binding occurs
229
- used: Literal[False] | tuple[Any, ast.AST], usage tracking
230
"""
231
232
def __init__(self, name: str, source: ast.AST | None) -> None: ...
233
def redefines(self, other: Binding) -> bool:
234
"""Check if this binding redefines another binding."""
235
236
class Definition(Binding):
237
"""Base class for name definitions."""
238
239
class Builtin(Definition):
240
"""Built-in name binding."""
241
def __init__(self, name: str) -> None: ...
242
```
243
244
#### Import Bindings
245
246
Specialized binding classes for different types of import statements.
247
248
```python { .api }
249
class Importation(Definition):
250
"""
251
Import statement binding.
252
253
Attributes:
254
- fullName: str, full module name
255
- redefined: list[Any], names redefined by this import
256
"""
257
258
def __init__(self, name: str, source: ast.AST | None, full_name: str | None = ...) -> None: ...
259
260
@property
261
def source_statement(self) -> str:
262
"""Source import statement text."""
263
264
class ImportationFrom(Importation):
265
"""
266
From-import binding.
267
268
Attributes:
269
- module: str, source module name
270
- real_name: str, actual imported name
271
"""
272
273
def __init__(self, name: str, source: ast.AST, module: str, real_name: str | None = ...) -> None: ...
274
275
class StarImportation(Importation):
276
"""Star import binding (from module import *)."""
277
def __init__(self, name: str, source: ast.AST) -> None: ...
278
279
class FutureImportation(ImportationFrom):
280
"""
281
Future import binding.
282
283
Attributes:
284
- used: tuple[Any, ast.AST], always marked as used
285
"""
286
def __init__(self, name: str, source: ast.AST, scope) -> None: ...
287
```
288
289
#### Other Binding Types
290
291
```python { .api }
292
class Argument(Binding):
293
"""Function argument binding."""
294
295
class Assignment(Binding):
296
"""Assignment binding."""
297
298
class Annotation(Binding):
299
"""Type annotation binding."""
300
def redefines(self, other: Binding) -> Literal[False]:
301
"""Annotations never redefine other bindings."""
302
303
class FunctionDefinition(Definition):
304
"""Function definition binding."""
305
306
class ClassDefinition(Definition):
307
"""Class definition binding."""
308
309
class ExportBinding(Binding):
310
"""
311
Export binding for __all__ declarations.
312
313
Attributes:
314
- names: list[str], exported names
315
"""
316
def __init__(self, name: str, source: ast.AST, scope: Scope) -> None: ...
317
```
318
319
### Scope Classes
320
321
Different types of scopes for tracking variable visibility and lifetime.
322
323
```python { .api }
324
class Scope(dict[str, Binding]):
325
"""
326
Base scope class mapping names to bindings.
327
328
Attributes:
329
- importStarred: bool, whether scope has star imports
330
"""
331
332
class ModuleScope(Scope):
333
"""Module-level scope."""
334
335
class FunctionScope(Scope):
336
"""
337
Function scope with additional function-specific tracking.
338
339
Attributes:
340
- usesLocals: bool, whether function uses locals()
341
- alwaysUsed: ClassVar[set[str]], names always considered used
342
- globals: set[str], names declared global
343
- returnValue: Any, return value tracking
344
- isGenerator: bool, whether function is a generator
345
"""
346
347
def __init__(self) -> None: ...
348
def unusedAssignments(self) -> Iterator[tuple[str, Binding]]:
349
"""Iterate over unused assignments in this scope."""
350
351
class ClassScope(Scope):
352
"""Class scope."""
353
354
class GeneratorScope(Scope):
355
"""Generator expression scope."""
356
357
class DoctestScope(ModuleScope):
358
"""Doctest block scope."""
359
```
360
361
### Utility Functions
362
363
Helper functions for AST analysis and format string parsing.
364
365
```python { .api }
366
def getAlternatives(n: ast.If | ast.Try) -> list[ast.AST]:
367
"""Get alternative execution branches from if/try statements."""
368
369
def counter(items: Iterable[_T]) -> dict[_T, int]:
370
"""Count occurrences of items in iterable."""
371
372
def iter_child_nodes(node: ast.AST, omit: _OmitType = ..., _fields_order: _FieldsOrder = ...) -> Iterator[ast.AST]:
373
"""Iterate over child AST nodes with optional field omission."""
374
375
def getNodeName(node: ast.AST) -> str:
376
"""Extract name from AST node."""
377
378
def is_typing_overload(value: Binding, scope_stack) -> bool:
379
"""Check if binding represents a typing.overload decorator."""
380
381
def parse_percent_format(s: str) -> tuple[_PercentFormat, ...]:
382
"""Parse percent-style format strings for validation."""
383
```
384
385
### Constants and Patterns
386
387
```python { .api }
388
# Python version compatibility
389
PY38_PLUS: bool
390
PYPY: bool
391
392
# AST node types
393
FOR_TYPES: tuple[type[ast.For], type[ast.AsyncFor]]
394
395
# Regular expression patterns
396
TYPE_COMMENT_RE: Pattern[str]
397
TYPE_IGNORE_RE: Pattern[str]
398
TYPE_FUNC_RE: Pattern[str]
399
MAPPING_KEY_RE: Pattern[str]
400
CONVERSION_FLAG_RE: Pattern[str]
401
WIDTH_RE: Pattern[str]
402
PRECISION_RE: Pattern[str]
403
LENGTH_RE: Pattern[str]
404
405
# String constants
406
ASCII_NON_ALNUM: str
407
VALID_CONVERSIONS: frozenset[str]
408
TYPING_MODULES: frozenset[Literal["typing", "typing_extensions"]]
409
```
410
411
**Usage Example:**
412
413
```python
414
import ast
415
from pyflakes.checker import Checker
416
from pyflakes.reporter import Reporter
417
import sys
418
419
# Parse Python code
420
code = """
421
import os
422
import sys
423
x = undefined_var
424
"""
425
426
tree = ast.parse(code)
427
reporter = Reporter(sys.stderr, sys.stderr)
428
429
# Create and run checker
430
checker = Checker(tree, "example.py")
431
print(f"Found {len(checker.messages)} issues")
432
433
# Access detailed analysis results
434
for message in checker.messages:
435
print(f"Line {message.lineno}: {message}")
436
```