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
« 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.
7from enum import auto, Enum
8from typing import Optional, Sequence
10import libcst as cst
11from libcst.metadata.base_provider import BatchableMetadataProvider
14class ExpressionContext(Enum):
15 """Used in :class:`ExpressionContextProvider` to represent context of a variable
16 reference."""
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()
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()
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()
55class ExpressionContextVisitor(cst.CSTVisitor):
56 def __init__(
57 self, provider: "ExpressionContextProvider", context: ExpressionContext
58 ) -> None:
59 self.provider = provider
60 self.context = context
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
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
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
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
94 def visit_Name(self, node: cst.Name) -> bool:
95 self.provider.set_metadata(node, self.context)
96 return False
98 def visit_AsName(self, node: cst.AsName) -> Optional[bool]:
99 node.name.visit(
100 ExpressionContextVisitor(self.provider, ExpressionContext.STORE)
101 )
102 return False
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
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
127 def visit_Del(self, node: cst.Del) -> bool:
128 node.target.visit(
129 ExpressionContextVisitor(self.provider, ExpressionContext.DEL)
130 )
131 return False
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
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
156 def visit_Tuple(self, node: cst.Tuple) -> Optional[bool]:
157 self.provider.set_metadata(node, self.context)
159 def visit_List(self, node: cst.List) -> Optional[bool]:
160 self.provider.set_metadata(node, self.context)
162 def visit_StarredElement(self, node: cst.StarredElement) -> Optional[bool]:
163 self.provider.set_metadata(node, self.context)
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
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
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
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`.
218 Three context types :attr:`ExpressionContext.STORE`,
219 :attr:`ExpressionContext.LOAD` and :attr:`ExpressionContext.DEL` are provided.
220 """
222 def visit_Module(self, node: cst.Module) -> Optional[bool]:
223 node.visit(ExpressionContextVisitor(self, ExpressionContext.LOAD))