Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/libcst/metadata/expression_context_provider.py: 27%

109 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-09-25 06:43 +0000

1# Copyright (c) Meta Platforms, Inc. and affiliates. 

2# 

3# This source code is licensed under the MIT license found in the 

4# LICENSE file in the root directory of this source tree. 

5 

6 

7from enum import auto, Enum 

8from typing import Optional, Sequence 

9 

10import libcst as cst 

11from libcst.metadata.base_provider import BatchableMetadataProvider 

12 

13 

14class ExpressionContext(Enum): 

15 """Used in :class:`ExpressionContextProvider` to represent context of a variable 

16 reference.""" 

17 

18 #: Load the value of a variable reference. 

19 #: 

20 #: >>> libcst.MetadataWrapper(libcst.parse_module("a")).resolve(libcst.ExpressionContextProvider) 

21 #: mappingproxy({Name( 

22 #: value='a', 

23 #: lpar=[], 

24 #: rpar=[], 

25 #: ): <ExpressionContext.LOAD: 1>}) 

26 LOAD = auto() 

27 

28 #: Store a value to a variable reference by :class:`~libcst.Assign` (``=``), 

29 #: :class:`~libcst.AugAssign` (e.g. ``+=``, ``-=``, etc), or 

30 #: :class:`~libcst.AnnAssign`. 

31 #: 

32 #: >>> libcst.MetadataWrapper(libcst.parse_module("a = b")).resolve(libcst.ExpressionContextProvider) 

33 #: mappingproxy({Name( 

34 #: value='a', 

35 #: lpar=[], 

36 #: rpar=[], 

37 #: ): <ExpressionContext.STORE: 2>, Name( 

38 #: value='b', 

39 #: lpar=[], 

40 #: rpar=[], 

41 #: ): <ExpressionContext.LOAD: 1>}) 

42 STORE = auto() 

43 

44 #: Delete value of a variable reference by ``del``. 

45 #: 

46 #: >>> libcst.MetadataWrapper(libcst.parse_module("del a")).resolve(libcst.ExpressionContextProvider) 

47 #: mappingproxy({Name( 

48 #: value='a', 

49 #: lpar=[], 

50 #: rpar=[], 

51 #: ): < ExpressionContext.DEL: 3 >}) 

52 DEL = auto() 

53 

54 

55class ExpressionContextVisitor(cst.CSTVisitor): 

56 def __init__( 

57 self, provider: "ExpressionContextProvider", context: ExpressionContext 

58 ) -> None: 

59 self.provider = provider 

60 self.context = context 

61 

62 def visit_Assign(self, node: cst.Assign) -> bool: 

63 for target in node.targets: 

64 target.visit( 

65 ExpressionContextVisitor(self.provider, ExpressionContext.STORE) 

66 ) 

67 node.value.visit(self) 

68 return False 

69 

70 def visit_AnnAssign(self, node: cst.AnnAssign) -> bool: 

71 node.target.visit( 

72 ExpressionContextVisitor(self.provider, ExpressionContext.STORE) 

73 ) 

74 node.annotation.visit(self) 

75 value = node.value 

76 if value: 

77 value.visit(self) 

78 return False 

79 

80 def visit_AugAssign(self, node: cst.AugAssign) -> bool: 

81 node.target.visit( 

82 ExpressionContextVisitor(self.provider, ExpressionContext.STORE) 

83 ) 

84 node.value.visit(self) 

85 return False 

86 

87 def visit_NamedExpr(self, node: cst.NamedExpr) -> bool: 

88 node.target.visit( 

89 ExpressionContextVisitor(self.provider, ExpressionContext.STORE) 

90 ) 

91 node.value.visit(self) 

92 return False 

93 

94 def visit_Name(self, node: cst.Name) -> bool: 

95 self.provider.set_metadata(node, self.context) 

96 return False 

97 

98 def visit_AsName(self, node: cst.AsName) -> Optional[bool]: 

99 node.name.visit( 

100 ExpressionContextVisitor(self.provider, ExpressionContext.STORE) 

101 ) 

102 return False 

103 

104 def visit_CompFor(self, node: cst.CompFor) -> bool: 

105 node.target.visit( 

106 ExpressionContextVisitor(self.provider, ExpressionContext.STORE) 

107 ) 

108 node.iter.visit(self) 

109 for i in node.ifs: 

110 i.visit(self) 

111 inner_for_in = node.inner_for_in 

112 if inner_for_in: 

113 inner_for_in.visit(self) 

114 return False 

115 

116 def visit_For(self, node: cst.For) -> bool: 

117 node.target.visit( 

118 ExpressionContextVisitor(self.provider, ExpressionContext.STORE) 

119 ) 

120 node.iter.visit(self) 

121 node.body.visit(self) 

122 orelse = node.orelse 

123 if orelse: 

124 orelse.visit(self) 

125 return False 

126 

127 def visit_Del(self, node: cst.Del) -> bool: 

128 node.target.visit( 

129 ExpressionContextVisitor(self.provider, ExpressionContext.DEL) 

130 ) 

131 return False 

132 

133 def visit_Attribute(self, node: cst.Attribute) -> bool: 

134 self.provider.set_metadata(node, self.context) 

135 node.value.visit( 

136 ExpressionContextVisitor(self.provider, ExpressionContext.LOAD) 

137 ) 

138 # don't visit attr (Name), so attr has no context 

139 return False 

140 

141 def visit_Subscript(self, node: cst.Subscript) -> bool: 

142 self.provider.set_metadata(node, self.context) 

143 node.value.visit( 

144 ExpressionContextVisitor(self.provider, ExpressionContext.LOAD) 

145 ) 

146 slice = node.slice 

147 if isinstance(slice, Sequence): 

148 for sli in slice: 

149 sli.visit( 

150 ExpressionContextVisitor(self.provider, ExpressionContext.LOAD) 

151 ) 

152 else: 

153 slice.visit(ExpressionContextVisitor(self.provider, ExpressionContext.LOAD)) 

154 return False 

155 

156 def visit_Tuple(self, node: cst.Tuple) -> Optional[bool]: 

157 self.provider.set_metadata(node, self.context) 

158 

159 def visit_List(self, node: cst.List) -> Optional[bool]: 

160 self.provider.set_metadata(node, self.context) 

161 

162 def visit_StarredElement(self, node: cst.StarredElement) -> Optional[bool]: 

163 self.provider.set_metadata(node, self.context) 

164 

165 def visit_ClassDef(self, node: cst.ClassDef) -> Optional[bool]: 

166 node.name.visit( 

167 ExpressionContextVisitor(self.provider, ExpressionContext.STORE) 

168 ) 

169 node.body.visit(self) 

170 for base in node.bases: 

171 base.visit(self) 

172 for keyword in node.keywords: 

173 keyword.visit(self) 

174 for decorator in node.decorators: 

175 decorator.visit(self) 

176 return False 

177 

178 def visit_FunctionDef(self, node: cst.FunctionDef) -> Optional[bool]: 

179 node.name.visit( 

180 ExpressionContextVisitor(self.provider, ExpressionContext.STORE) 

181 ) 

182 node.params.visit(self) 

183 node.body.visit(self) 

184 for decorator in node.decorators: 

185 decorator.visit(self) 

186 returns = node.returns 

187 if returns: 

188 returns.visit(self) 

189 return False 

190 

191 def visit_Param(self, node: cst.Param) -> Optional[bool]: 

192 node.name.visit( 

193 ExpressionContextVisitor(self.provider, ExpressionContext.STORE) 

194 ) 

195 annotation = node.annotation 

196 if annotation: 

197 annotation.visit(self) 

198 default = node.default 

199 if default: 

200 default.visit(self) 

201 return False 

202 

203 

204class ExpressionContextProvider(BatchableMetadataProvider[ExpressionContext]): 

205 """ 

206 Provides :class:`ExpressionContext` metadata (mimics the `expr_context 

207 <https://docs.python.org/3/library/ast.html>`__ in ast) for the 

208 following node types: 

209 :class:`~libcst.Attribute`, :class:`~libcst.Subscript`, 

210 :class:`~libcst.StarredElement` , :class:`~libcst.List`, 

211 :class:`~libcst.Tuple` and :class:`~libcst.Name`. 

212 Note that a :class:`~libcst.Name` may not always have context because of the differences between 

213 ast and LibCST. E.g. :attr:`~libcst.Attribute.attr` is a :class:`~libcst.Name` in LibCST 

214 but a str in ast. To honor ast implementation, we don't assign context to 

215 :attr:`~libcst.Attribute.attr`. 

216 

217 

218 Three context types :attr:`ExpressionContext.STORE`, 

219 :attr:`ExpressionContext.LOAD` and :attr:`ExpressionContext.DEL` are provided. 

220 """ 

221 

222 def visit_Module(self, node: cst.Module) -> Optional[bool]: 

223 node.visit(ExpressionContextVisitor(self, ExpressionContext.LOAD))