66
77from __future__ import annotations
88
9- from typing import TYPE_CHECKING
9+ from collections .abc import Sequence
10+ from typing import TYPE_CHECKING , Any , TypeVar , Union
1011
1112from astroid import nodes
1213from mccabe import PathGraph as Mccabe_PathGraph
1920if TYPE_CHECKING :
2021 from pylint .lint import PyLinter
2122
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+
2247
2348class PathGraph (Mccabe_PathGraph ):
24- def __init__ (self , node ):
49+ def __init__ (self , node : _SubGraphNodes | nodes . FunctionDef ):
2550 super ().__init__ (name = "" , entity = "" , lineno = 1 )
2651 self .root = node
2752
2853
2954class PathGraphingAstVisitor (Mccabe_PathGraphingAstVisitor ):
30- def __init__ (self ):
55+ def __init__ (self ) -> None :
3156 super ().__init__ ()
3257 self ._bottom_counter = 0
58+ self .graph : PathGraph | None = None
3359
34- def default (self , node , * args ) :
60+ def default (self , node : nodes . NodeNG , * args : Any ) -> None :
3561 for child in node .get_children ():
3662 self .dispatch (child , * args )
3763
38- def dispatch (self , node , * args ) :
64+ def dispatch (self , node : nodes . NodeNG , * args : Any ) -> Any :
3965 self .node = node
4066 klass = node .__class__
4167 meth = self ._cache .get (klass )
@@ -45,7 +71,7 @@ def dispatch(self, node, *args):
4571 self ._cache [klass ] = meth
4672 return meth (node , * args )
4773
48- def visitFunctionDef (self , node ) :
74+ def visitFunctionDef (self , node : nodes . FunctionDef ) -> None :
4975 if self .graph is not None :
5076 # closure
5177 pathnode = self ._append_node (node )
@@ -65,7 +91,7 @@ def visitFunctionDef(self, node):
6591
6692 visitAsyncFunctionDef = visitFunctionDef
6793
68- def visitSimpleStatement (self , node ) :
94+ def visitSimpleStatement (self , node : _StatementNodes ) -> None :
6995 self ._append_node (node )
7096
7197 visitAssert = (
@@ -74,8 +100,6 @@ def visitSimpleStatement(self, node):
74100 visitAugAssign
75101 ) = (
76102 visitDelete
77- ) = (
78- visitPrint
79103 ) = (
80104 visitRaise
81105 ) = (
@@ -94,20 +118,25 @@ def visitSimpleStatement(self, node):
94118 visitBreak
95119 ) = visitGlobal = visitReturn = visitExpr = visitAwait = visitSimpleStatement
96120
97- def visitWith (self , node ) :
121+ def visitWith (self , node : nodes . With ) -> None :
98122 self ._append_node (node )
99123 self .dispatch_list (node .body )
100124
101125 visitAsyncWith = visitWith
102126
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 :
105129 return None
106130 self .graph .connect (self .tail , node )
107131 self .tail = node
108132 return node
109133
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 :
111140 """Create the subgraphs representing any `if` and `for` statements."""
112141 if self .graph is None :
113142 # global loop
@@ -119,7 +148,12 @@ def _subgraph(self, node, name, extra_blocks=()):
119148 self ._append_node (node )
120149 self ._subgraph_parse (node , node , extra_blocks )
121150
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 :
123157 """Parse the body and any `else` block of `if` and `for` statements."""
124158 loose_ends = []
125159 self .tail = node
@@ -135,7 +169,7 @@ def _subgraph_parse(self, node, pathnode, extra_blocks):
135169 loose_ends .append (self .tail )
136170 else :
137171 loose_ends .append (node )
138- if node :
172+ if node and self . graph :
139173 bottom = f"{ self ._bottom_counter } "
140174 self ._bottom_counter += 1
141175 for end in loose_ends :
0 commit comments