6
6
7
7
from __future__ import annotations
8
8
9
- from typing import TYPE_CHECKING
9
+ from collections .abc import Sequence
10
+ from typing import TYPE_CHECKING , Any , TypeVar , Union
10
11
11
12
from astroid import nodes
12
13
from mccabe import PathGraph as Mccabe_PathGraph
19
20
if TYPE_CHECKING :
20
21
from pylint .lint import PyLinter
21
22
23
+ _StatementNodes = Union [
24
+ nodes .Assert ,
25
+ nodes .Assign ,
26
+ nodes .AugAssign ,
27
+ nodes .Delete ,
28
+ nodes .Raise ,
29
+ nodes .Yield ,
30
+ nodes .Import ,
31
+ nodes .Call ,
32
+ nodes .Subscript ,
33
+ nodes .Pass ,
34
+ nodes .Continue ,
35
+ nodes .Break ,
36
+ nodes .Global ,
37
+ nodes .Return ,
38
+ nodes .Expr ,
39
+ nodes .Await ,
40
+ ]
41
+
42
+ _SubGraphNodes = Union [nodes .If , nodes .TryExcept , nodes .For , nodes .While ]
43
+ _AppendableNodeT = TypeVar (
44
+ "_AppendableNodeT" , bound = Union [_StatementNodes , nodes .While , nodes .FunctionDef ]
45
+ )
46
+
22
47
23
48
class PathGraph (Mccabe_PathGraph ):
24
- def __init__ (self , node ):
49
+ def __init__ (self , node : _SubGraphNodes | nodes . FunctionDef ):
25
50
super ().__init__ (name = "" , entity = "" , lineno = 1 )
26
51
self .root = node
27
52
28
53
29
54
class PathGraphingAstVisitor (Mccabe_PathGraphingAstVisitor ):
30
- def __init__ (self ):
55
+ def __init__ (self ) -> None :
31
56
super ().__init__ ()
32
57
self ._bottom_counter = 0
58
+ self .graph : PathGraph | None = None
33
59
34
- def default (self , node , * args ) :
60
+ def default (self , node : nodes . NodeNG , * args : Any ) -> None :
35
61
for child in node .get_children ():
36
62
self .dispatch (child , * args )
37
63
38
- def dispatch (self , node , * args ) :
64
+ def dispatch (self , node : nodes . NodeNG , * args : Any ) -> Any :
39
65
self .node = node
40
66
klass = node .__class__
41
67
meth = self ._cache .get (klass )
@@ -45,7 +71,7 @@ def dispatch(self, node, *args):
45
71
self ._cache [klass ] = meth
46
72
return meth (node , * args )
47
73
48
- def visitFunctionDef (self , node ) :
74
+ def visitFunctionDef (self , node : nodes . FunctionDef ) -> None :
49
75
if self .graph is not None :
50
76
# closure
51
77
pathnode = self ._append_node (node )
@@ -65,7 +91,7 @@ def visitFunctionDef(self, node):
65
91
66
92
visitAsyncFunctionDef = visitFunctionDef
67
93
68
- def visitSimpleStatement (self , node ) :
94
+ def visitSimpleStatement (self , node : _StatementNodes ) -> None :
69
95
self ._append_node (node )
70
96
71
97
visitAssert = (
@@ -74,8 +100,6 @@ def visitSimpleStatement(self, node):
74
100
visitAugAssign
75
101
) = (
76
102
visitDelete
77
- ) = (
78
- visitPrint
79
103
) = (
80
104
visitRaise
81
105
) = (
@@ -94,20 +118,25 @@ def visitSimpleStatement(self, node):
94
118
visitBreak
95
119
) = visitGlobal = visitReturn = visitExpr = visitAwait = visitSimpleStatement
96
120
97
- def visitWith (self , node ) :
121
+ def visitWith (self , node : nodes . With ) -> None :
98
122
self ._append_node (node )
99
123
self .dispatch_list (node .body )
100
124
101
125
visitAsyncWith = visitWith
102
126
103
- def _append_node (self , node ) :
104
- if not self .tail :
127
+ def _append_node (self , node : _AppendableNodeT ) -> _AppendableNodeT | None :
128
+ if not self .tail or not self . graph :
105
129
return None
106
130
self .graph .connect (self .tail , node )
107
131
self .tail = node
108
132
return node
109
133
110
- def _subgraph (self , node , name , extra_blocks = ()):
134
+ def _subgraph (
135
+ self ,
136
+ node : _SubGraphNodes ,
137
+ name : str ,
138
+ extra_blocks : Sequence [nodes .ExceptHandler ] = (),
139
+ ) -> None :
111
140
"""Create the subgraphs representing any `if` and `for` statements."""
112
141
if self .graph is None :
113
142
# global loop
@@ -119,7 +148,12 @@ def _subgraph(self, node, name, extra_blocks=()):
119
148
self ._append_node (node )
120
149
self ._subgraph_parse (node , node , extra_blocks )
121
150
122
- def _subgraph_parse (self , node , pathnode , extra_blocks ):
151
+ def _subgraph_parse (
152
+ self ,
153
+ node : _SubGraphNodes ,
154
+ pathnode : _SubGraphNodes ,
155
+ extra_blocks : Sequence [nodes .ExceptHandler ],
156
+ ) -> None :
123
157
"""Parse the body and any `else` block of `if` and `for` statements."""
124
158
loose_ends = []
125
159
self .tail = node
@@ -135,7 +169,7 @@ def _subgraph_parse(self, node, pathnode, extra_blocks):
135
169
loose_ends .append (self .tail )
136
170
else :
137
171
loose_ends .append (node )
138
- if node :
172
+ if node and self . graph :
139
173
bottom = f"{ self ._bottom_counter } "
140
174
self ._bottom_counter += 1
141
175
for end in loose_ends :
0 commit comments