OLD | NEW |
1 # copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. | 1 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr | 2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
| 3 # copyright 2003-2010 Sylvain Thenault, all rights reserved. |
| 4 # contact mailto:thenault@gmail.com |
3 # | 5 # |
4 # This file is part of astroid. | 6 # This file is part of logilab-astng. |
5 # | 7 # |
6 # astroid is free software: you can redistribute it and/or modify it | 8 # logilab-astng is free software: you can redistribute it and/or modify it |
7 # under the terms of the GNU Lesser General Public License as published by the | 9 # under the terms of the GNU Lesser General Public License as published by the |
8 # Free Software Foundation, either version 2.1 of the License, or (at your | 10 # Free Software Foundation, either version 2.1 of the License, or (at your |
9 # option) any later version. | 11 # option) any later version. |
10 # | 12 # |
11 # astroid is distributed in the hope that it will be useful, but | 13 # logilab-astng is distributed in the hope that it will be useful, but |
12 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 14 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License | 15 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License |
14 # for more details. | 16 # for more details. |
15 # | 17 # |
16 # You should have received a copy of the GNU Lesser General Public License along | 18 # You should have received a copy of the GNU Lesser General Public License along |
17 # with astroid. If not, see <http://www.gnu.org/licenses/>. | 19 # with logilab-astng. If not, see <http://www.gnu.org/licenses/>. |
18 """this module contains a set of functions to handle python protocols for nodes | 20 """this module contains a set of functions to handle python protocols for nodes |
19 where it makes sense. | 21 where it makes sense. |
20 """ | 22 """ |
21 | 23 |
22 __doctype__ = "restructuredtext en" | 24 __doctype__ = "restructuredtext en" |
23 | 25 |
24 from astroid.exceptions import InferenceError, NoDefault, NotFoundError | 26 from logilab.astng.exceptions import InferenceError, NoDefault |
25 from astroid.node_classes import unpack_infer | 27 from logilab.astng.node_classes import unpack_infer |
26 from astroid.bases import copy_context, \ | 28 from logilab.astng.bases import copy_context, \ |
27 raise_if_nothing_infered, yes_if_nothing_infered, Instance, YES | 29 raise_if_nothing_infered, yes_if_nothing_infered, Instance, Generator, YES |
28 from astroid.nodes import const_factory | 30 from logilab.astng.nodes import const_factory |
29 from astroid import nodes | 31 from logilab.astng import nodes |
30 | |
31 BIN_OP_METHOD = {'+': '__add__', | |
32 '-': '__sub__', | |
33 '/': '__div__', | |
34 '//': '__floordiv__', | |
35 '*': '__mul__', | |
36 '**': '__power__', | |
37 '%': '__mod__', | |
38 '&': '__and__', | |
39 '|': '__or__', | |
40 '^': '__xor__', | |
41 '<<': '__lshift__', | |
42 '>>': '__rshift__', | |
43 } | |
44 | |
45 UNARY_OP_METHOD = {'+': '__pos__', | |
46 '-': '__neg__', | |
47 '~': '__invert__', | |
48 'not': None, # XXX not '__nonzero__' | |
49 } | |
50 | 32 |
51 # unary operations ############################################################ | 33 # unary operations ############################################################ |
52 | 34 |
53 def tl_infer_unary_op(self, operator): | 35 def tl_infer_unary_op(self, operator): |
54 if operator == 'not': | 36 if operator == 'not': |
55 return const_factory(not bool(self.elts)) | 37 return const_factory(not bool(self.elts)) |
56 raise TypeError() # XXX log unsupported operation | 38 raise TypeError() # XXX log unsupported operation |
57 nodes.Tuple.infer_unary_op = tl_infer_unary_op | 39 nodes.Tuple.infer_unary_op = tl_infer_unary_op |
58 nodes.List.infer_unary_op = tl_infer_unary_op | 40 nodes.List.infer_unary_op = tl_infer_unary_op |
59 | 41 |
(...skipping 23 matching lines...) Expand all Loading... |
83 '/': lambda a, b: a / b, | 65 '/': lambda a, b: a / b, |
84 '//': lambda a, b: a // b, | 66 '//': lambda a, b: a // b, |
85 '*': lambda a, b: a * b, | 67 '*': lambda a, b: a * b, |
86 '**': lambda a, b: a ** b, | 68 '**': lambda a, b: a ** b, |
87 '%': lambda a, b: a % b, | 69 '%': lambda a, b: a % b, |
88 '&': lambda a, b: a & b, | 70 '&': lambda a, b: a & b, |
89 '|': lambda a, b: a | b, | 71 '|': lambda a, b: a | b, |
90 '^': lambda a, b: a ^ b, | 72 '^': lambda a, b: a ^ b, |
91 '<<': lambda a, b: a << b, | 73 '<<': lambda a, b: a << b, |
92 '>>': lambda a, b: a >> b, | 74 '>>': lambda a, b: a >> b, |
93 } | 75 } |
94 for key, impl in BIN_OP_IMPL.items(): | 76 for key, impl in BIN_OP_IMPL.items(): |
95 BIN_OP_IMPL[key+'='] = impl | 77 BIN_OP_IMPL[key+'='] = impl |
96 | 78 |
97 def const_infer_binary_op(self, operator, other, context): | 79 def const_infer_binary_op(self, operator, other, context): |
98 for other in other.infer(context): | 80 for other in other.infer(context): |
99 if isinstance(other, nodes.Const): | 81 if isinstance(other, nodes.Const): |
100 try: | 82 try: |
101 impl = BIN_OP_IMPL[operator] | 83 impl = BIN_OP_IMPL[operator] |
102 | 84 |
103 try: | 85 try: |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
146 nodes.List.infer_binary_op = yes_if_nothing_infered(tl_infer_binary_op) | 128 nodes.List.infer_binary_op = yes_if_nothing_infered(tl_infer_binary_op) |
147 | 129 |
148 | 130 |
149 def dict_infer_binary_op(self, operator, other, context): | 131 def dict_infer_binary_op(self, operator, other, context): |
150 for other in other.infer(context): | 132 for other in other.infer(context): |
151 if isinstance(other, Instance) and isinstance(other._proxied, nodes.Clas
s): | 133 if isinstance(other, Instance) and isinstance(other._proxied, nodes.Clas
s): |
152 yield YES | 134 yield YES |
153 # XXX else log TypeError | 135 # XXX else log TypeError |
154 nodes.Dict.infer_binary_op = yes_if_nothing_infered(dict_infer_binary_op) | 136 nodes.Dict.infer_binary_op = yes_if_nothing_infered(dict_infer_binary_op) |
155 | 137 |
156 def instance_infer_binary_op(self, operator, other, context): | |
157 try: | |
158 methods = self.getattr(BIN_OP_METHOD[operator]) | |
159 except (NotFoundError, KeyError): | |
160 # Unknown operator | |
161 yield YES | |
162 else: | |
163 for method in methods: | |
164 if not isinstance(method, nodes.Function): | |
165 continue | |
166 for result in method.infer_call_result(self, context): | |
167 if result is not YES: | |
168 yield result | |
169 # We are interested only in the first infered method, | |
170 # don't go looking in the rest of the methods of the ancestors. | |
171 break | |
172 | |
173 Instance.infer_binary_op = yes_if_nothing_infered(instance_infer_binary_op) | |
174 | |
175 | 138 |
176 # assignment ################################################################## | 139 # assignment ################################################################## |
177 | 140 |
178 """the assigned_stmts method is responsible to return the assigned statement | 141 """the assigned_stmts method is responsible to return the assigned statement |
179 (e.g. not inferred) according to the assignment type. | 142 (e.g. not inferred) according to the assignment type. |
180 | 143 |
181 The `asspath` argument is used to record the lhs path of the original node. | 144 The `asspath` argument is used to record the lhs path of the original node. |
182 For instance if we want assigned statements for 'c' in 'a, (b,c)', asspath | 145 For instance if we want assigned statements for 'c' in 'a, (b,c)', asspath |
183 will be [1, 1] once arrived to the Assign node. | 146 will be [1, 1] once arrived to the Assign node. |
184 | 147 |
(...skipping 13 matching lines...) Expand all Loading... |
198 continue | 161 continue |
199 try: | 162 try: |
200 itered = part.itered() | 163 itered = part.itered() |
201 except TypeError: | 164 except TypeError: |
202 continue # XXX log error | 165 continue # XXX log error |
203 for stmt in itered: | 166 for stmt in itered: |
204 try: | 167 try: |
205 assigned = stmt.getitem(index, context) | 168 assigned = stmt.getitem(index, context) |
206 except (AttributeError, IndexError): | 169 except (AttributeError, IndexError): |
207 continue | 170 continue |
208 except TypeError: # stmt is unsubscriptable Const | 171 except TypeError, exc: # stmt is unsubscriptable Const |
209 continue | 172 continue |
210 if not asspath: | 173 if not asspath: |
211 # we achieved to resolved the assignment path, | 174 # we achieved to resolved the assignment path, |
212 # don't infer the last part | 175 # don't infer the last part |
213 yield assigned | 176 yield assigned |
214 elif assigned is YES: | 177 elif assigned is YES: |
215 break | 178 break |
216 else: | 179 else: |
217 # we are not yet on the last part of the path | 180 # we are not yet on the last part of the path |
218 # search on each possibly inferred value | 181 # search on each possibly inferred value |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
263 # first argument of instance/class method | 226 # first argument of instance/class method |
264 if self.args and getattr(self.args[0], 'name', None) == name: | 227 if self.args and getattr(self.args[0], 'name', None) == name: |
265 functype = self.parent.type | 228 functype = self.parent.type |
266 if functype == 'method': | 229 if functype == 'method': |
267 yield Instance(self.parent.parent.frame()) | 230 yield Instance(self.parent.parent.frame()) |
268 return | 231 return |
269 if functype == 'classmethod': | 232 if functype == 'classmethod': |
270 yield self.parent.parent.frame() | 233 yield self.parent.parent.frame() |
271 return | 234 return |
272 if name == self.vararg: | 235 if name == self.vararg: |
273 vararg = const_factory(()) | 236 yield const_factory(()) |
274 vararg.parent = self | |
275 yield vararg | |
276 return | 237 return |
277 if name == self.kwarg: | 238 if name == self.kwarg: |
278 kwarg = const_factory({}) | 239 yield const_factory({}) |
279 kwarg.parent = self | |
280 yield kwarg | |
281 return | 240 return |
282 # if there is a default value, yield it. And then yield YES to reflect | 241 # if there is a default value, yield it. And then yield YES to reflect |
283 # we can't guess given argument value | 242 # we can't guess given argument value |
284 try: | 243 try: |
285 context = copy_context(context) | 244 context = copy_context(context) |
286 for infered in self.default_value(name).infer(context): | 245 for infered in self.default_value(name).infer(context): |
287 yield infered | 246 yield infered |
288 yield YES | 247 yield YES |
289 except NoDefault: | 248 except NoDefault: |
290 yield YES | 249 yield YES |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
346 def excepthandler_assigned_stmts(self, node, context=None, asspath=None): | 305 def excepthandler_assigned_stmts(self, node, context=None, asspath=None): |
347 for assigned in unpack_infer(self.type): | 306 for assigned in unpack_infer(self.type): |
348 if isinstance(assigned, nodes.Class): | 307 if isinstance(assigned, nodes.Class): |
349 assigned = Instance(assigned) | 308 assigned = Instance(assigned) |
350 yield assigned | 309 yield assigned |
351 nodes.ExceptHandler.assigned_stmts = raise_if_nothing_infered(excepthandler_assi
gned_stmts) | 310 nodes.ExceptHandler.assigned_stmts = raise_if_nothing_infered(excepthandler_assi
gned_stmts) |
352 | 311 |
353 | 312 |
354 def with_assigned_stmts(self, node, context=None, asspath=None): | 313 def with_assigned_stmts(self, node, context=None, asspath=None): |
355 if asspath is None: | 314 if asspath is None: |
356 for _, vars in self.items: | 315 for lst in self.vars.infer(context): |
357 if vars is None: | 316 if isinstance(lst, (nodes.Tuple, nodes.List)): |
358 continue | 317 for item in lst.nodes: |
359 for lst in vars.infer(context): | 318 yield item |
360 if isinstance(lst, (nodes.Tuple, nodes.List)): | |
361 for item in lst.nodes: | |
362 yield item | |
363 nodes.With.assigned_stmts = raise_if_nothing_infered(with_assigned_stmts) | 319 nodes.With.assigned_stmts = raise_if_nothing_infered(with_assigned_stmts) |
364 | 320 |
365 | 321 |
OLD | NEW |