]> crepu.dev Git - config.git/blame - djavu-asus/elpy/rpc-venv/lib/python3.11/site-packages/jedi/inference/value/function.py
Archivo de configuraciĆ³n de la terminal
[config.git] / djavu-asus / elpy / rpc-venv / lib / python3.11 / site-packages / jedi / inference / value / function.py
CommitLineData
53e6db90
DC
1from parso.python import tree
2
3from jedi import debug
4from jedi.inference.cache import inference_state_method_cache, CachedMetaClass
5from jedi.inference import compiled
6from jedi.inference import recursion
7from jedi.inference import docstrings
8from jedi.inference import flow_analysis
9from jedi.inference.signature import TreeSignature
10from jedi.inference.filters import ParserTreeFilter, FunctionExecutionFilter, \
11 AnonymousFunctionExecutionFilter
12from jedi.inference.names import ValueName, AbstractNameDefinition, \
13 AnonymousParamName, ParamName, NameWrapper
14from jedi.inference.base_value import ContextualizedNode, NO_VALUES, \
15 ValueSet, TreeValue, ValueWrapper
16from jedi.inference.lazy_value import LazyKnownValues, LazyKnownValue, \
17 LazyTreeValue
18from jedi.inference.context import ValueContext, TreeContextMixin
19from jedi.inference.value import iterable
20from jedi import parser_utils
21from jedi.inference.parser_cache import get_yield_exprs
22from jedi.inference.helpers import values_from_qualified_names
23from jedi.inference.gradual.generics import TupleGenericManager
24
25
26class LambdaName(AbstractNameDefinition):
27 string_name = '<lambda>'
28 api_type = 'function'
29
30 def __init__(self, lambda_value):
31 self._lambda_value = lambda_value
32 self.parent_context = lambda_value.parent_context
33
34 @property
35 def start_pos(self):
36 return self._lambda_value.tree_node.start_pos
37
38 def infer(self):
39 return ValueSet([self._lambda_value])
40
41
42class FunctionAndClassBase(TreeValue):
43 def get_qualified_names(self):
44 if self.parent_context.is_class():
45 n = self.parent_context.get_qualified_names()
46 if n is None:
47 # This means that the parent class lives within a function.
48 return None
49 return n + (self.py__name__(),)
50 elif self.parent_context.is_module():
51 return (self.py__name__(),)
52 else:
53 return None
54
55
56class FunctionMixin:
57 api_type = 'function'
58
59 def get_filters(self, origin_scope=None):
60 cls = self.py__class__()
61 for instance in cls.execute_with_values():
62 yield from instance.get_filters(origin_scope=origin_scope)
63
64 def py__get__(self, instance, class_value):
65 from jedi.inference.value.instance import BoundMethod
66 if instance is None:
67 # Calling the Foo.bar results in the original bar function.
68 return ValueSet([self])
69 return ValueSet([BoundMethod(instance, class_value.as_context(), self)])
70
71 def get_param_names(self):
72 return [AnonymousParamName(self, param.name)
73 for param in self.tree_node.get_params()]
74
75 @property
76 def name(self):
77 if self.tree_node.type == 'lambdef':
78 return LambdaName(self)
79 return ValueName(self, self.tree_node.name)
80
81 def is_function(self):
82 return True
83
84 def py__name__(self):
85 return self.name.string_name
86
87 def get_type_hint(self, add_class_info=True):
88 return_annotation = self.tree_node.annotation
89 if return_annotation is None:
90 def param_name_to_str(n):
91 s = n.string_name
92 annotation = n.infer().get_type_hint()
93 if annotation is not None:
94 s += ': ' + annotation
95 if n.default_node is not None:
96 s += '=' + n.default_node.get_code(include_prefix=False)
97 return s
98
99 function_execution = self.as_context()
100 result = function_execution.infer()
101 return_hint = result.get_type_hint()
102 body = self.py__name__() + '(%s)' % ', '.join([
103 param_name_to_str(n)
104 for n in function_execution.get_param_names()
105 ])
106 if return_hint is None:
107 return body
108 else:
109 return_hint = return_annotation.get_code(include_prefix=False)
110 body = self.py__name__() + self.tree_node.children[2].get_code(include_prefix=False)
111
112 return body + ' -> ' + return_hint
113
114 def py__call__(self, arguments):
115 function_execution = self.as_context(arguments)
116 return function_execution.infer()
117
118 def _as_context(self, arguments=None):
119 if arguments is None:
120 return AnonymousFunctionExecution(self)
121 return FunctionExecutionContext(self, arguments)
122
123 def get_signatures(self):
124 return [TreeSignature(f) for f in self.get_signature_functions()]
125
126
127class FunctionValue(FunctionMixin, FunctionAndClassBase, metaclass=CachedMetaClass):
128 @classmethod
129 def from_context(cls, context, tree_node):
130 def create(tree_node):
131 if context.is_class():
132 return MethodValue(
133 context.inference_state,
134 context,
135 parent_context=parent_context,
136 tree_node=tree_node
137 )
138 else:
139 return cls(
140 context.inference_state,
141 parent_context=parent_context,
142 tree_node=tree_node
143 )
144
145 overloaded_funcs = list(_find_overload_functions(context, tree_node))
146
147 parent_context = context
148 while parent_context.is_class() or parent_context.is_instance():
149 parent_context = parent_context.parent_context
150
151 function = create(tree_node)
152
153 if overloaded_funcs:
154 return OverloadedFunctionValue(
155 function,
156 # Get them into the correct order: lower line first.
157 list(reversed([create(f) for f in overloaded_funcs]))
158 )
159 return function
160
161 def py__class__(self):
162 c, = values_from_qualified_names(self.inference_state, 'types', 'FunctionType')
163 return c
164
165 def get_default_param_context(self):
166 return self.parent_context
167
168 def get_signature_functions(self):
169 return [self]
170
171
172class FunctionNameInClass(NameWrapper):
173 def __init__(self, class_context, name):
174 super().__init__(name)
175 self._class_context = class_context
176
177 def get_defining_qualified_value(self):
178 return self._class_context.get_value() # Might be None.
179
180
181class MethodValue(FunctionValue):
182 def __init__(self, inference_state, class_context, *args, **kwargs):
183 super().__init__(inference_state, *args, **kwargs)
184 self.class_context = class_context
185
186 def get_default_param_context(self):
187 return self.class_context
188
189 def get_qualified_names(self):
190 # Need to implement this, because the parent value of a method
191 # value is not the class value but the module.
192 names = self.class_context.get_qualified_names()
193 if names is None:
194 return None
195 return names + (self.py__name__(),)
196
197 @property
198 def name(self):
199 return FunctionNameInClass(self.class_context, super().name)
200
201
202class BaseFunctionExecutionContext(ValueContext, TreeContextMixin):
203 def infer_annotations(self):
204 raise NotImplementedError
205
206 @inference_state_method_cache(default=NO_VALUES)
207 @recursion.execution_recursion_decorator()
208 def get_return_values(self, check_yields=False):
209 funcdef = self.tree_node
210 if funcdef.type == 'lambdef':
211 return self.infer_node(funcdef.children[-1])
212
213 if check_yields:
214 value_set = NO_VALUES
215 returns = get_yield_exprs(self.inference_state, funcdef)
216 else:
217 value_set = self.infer_annotations()
218 if value_set:
219 # If there are annotations, prefer them over anything else.
220 # This will make it faster.
221 return value_set
222 value_set |= docstrings.infer_return_types(self._value)
223 returns = funcdef.iter_return_stmts()
224
225 for r in returns:
226 if check_yields:
227 value_set |= ValueSet.from_sets(
228 lazy_value.infer()
229 for lazy_value in self._get_yield_lazy_value(r)
230 )
231 else:
232 check = flow_analysis.reachability_check(self, funcdef, r)
233 if check is flow_analysis.UNREACHABLE:
234 debug.dbg('Return unreachable: %s', r)
235 else:
236 try:
237 children = r.children
238 except AttributeError:
239 ctx = compiled.builtin_from_name(self.inference_state, 'None')
240 value_set |= ValueSet([ctx])
241 else:
242 value_set |= self.infer_node(children[1])
243 if check is flow_analysis.REACHABLE:
244 debug.dbg('Return reachable: %s', r)
245 break
246 return value_set
247
248 def _get_yield_lazy_value(self, yield_expr):
249 if yield_expr.type == 'keyword':
250 # `yield` just yields None.
251 ctx = compiled.builtin_from_name(self.inference_state, 'None')
252 yield LazyKnownValue(ctx)
253 return
254
255 node = yield_expr.children[1]
256 if node.type == 'yield_arg': # It must be a yield from.
257 cn = ContextualizedNode(self, node.children[1])
258 yield from cn.infer().iterate(cn)
259 else:
260 yield LazyTreeValue(self, node)
261
262 @recursion.execution_recursion_decorator(default=iter([]))
263 def get_yield_lazy_values(self, is_async=False):
264 # TODO: if is_async, wrap yield statements in Awaitable/async_generator_asend
265 for_parents = [(y, tree.search_ancestor(y, 'for_stmt', 'funcdef',
266 'while_stmt', 'if_stmt'))
267 for y in get_yield_exprs(self.inference_state, self.tree_node)]
268
269 # Calculate if the yields are placed within the same for loop.
270 yields_order = []
271 last_for_stmt = None
272 for yield_, for_stmt in for_parents:
273 # For really simple for loops we can predict the order. Otherwise
274 # we just ignore it.
275 parent = for_stmt.parent
276 if parent.type == 'suite':
277 parent = parent.parent
278 if for_stmt.type == 'for_stmt' and parent == self.tree_node \
279 and parser_utils.for_stmt_defines_one_name(for_stmt): # Simplicity for now.
280 if for_stmt == last_for_stmt:
281 yields_order[-1][1].append(yield_)
282 else:
283 yields_order.append((for_stmt, [yield_]))
284 elif for_stmt == self.tree_node:
285 yields_order.append((None, [yield_]))
286 else:
287 types = self.get_return_values(check_yields=True)
288 if types:
289 yield LazyKnownValues(types, min=0, max=float('inf'))
290 return
291 last_for_stmt = for_stmt
292
293 for for_stmt, yields in yields_order:
294 if for_stmt is None:
295 # No for_stmt, just normal yields.
296 for yield_ in yields:
297 yield from self._get_yield_lazy_value(yield_)
298 else:
299 input_node = for_stmt.get_testlist()
300 cn = ContextualizedNode(self, input_node)
301 ordered = cn.infer().iterate(cn)
302 ordered = list(ordered)
303 for lazy_value in ordered:
304 dct = {str(for_stmt.children[1].value): lazy_value.infer()}
305 with self.predefine_names(for_stmt, dct):
306 for yield_in_same_for_stmt in yields:
307 yield from self._get_yield_lazy_value(yield_in_same_for_stmt)
308
309 def merge_yield_values(self, is_async=False):
310 return ValueSet.from_sets(
311 lazy_value.infer()
312 for lazy_value in self.get_yield_lazy_values()
313 )
314
315 def is_generator(self):
316 return bool(get_yield_exprs(self.inference_state, self.tree_node))
317
318 def infer(self):
319 """
320 Created to be used by inheritance.
321 """
322 inference_state = self.inference_state
323 is_coroutine = self.tree_node.parent.type in ('async_stmt', 'async_funcdef')
324 from jedi.inference.gradual.base import GenericClass
325
326 if is_coroutine:
327 if self.is_generator():
328 async_generator_classes = inference_state.typing_module \
329 .py__getattribute__('AsyncGenerator')
330
331 yield_values = self.merge_yield_values(is_async=True)
332 # The contravariant doesn't seem to be defined.
333 generics = (yield_values.py__class__(), NO_VALUES)
334 return ValueSet(
335 GenericClass(c, TupleGenericManager(generics))
336 for c in async_generator_classes
337 ).execute_annotation()
338 else:
339 async_classes = inference_state.typing_module.py__getattribute__('Coroutine')
340 return_values = self.get_return_values()
341 # Only the first generic is relevant.
342 generics = (return_values.py__class__(), NO_VALUES, NO_VALUES)
343 return ValueSet(
344 GenericClass(c, TupleGenericManager(generics)) for c in async_classes
345 ).execute_annotation()
346 else:
347 # If there are annotations, prefer them over anything else.
348 if self.is_generator() and not self.infer_annotations():
349 return ValueSet([iterable.Generator(inference_state, self)])
350 else:
351 return self.get_return_values()
352
353
354class FunctionExecutionContext(BaseFunctionExecutionContext):
355 def __init__(self, function_value, arguments):
356 super().__init__(function_value)
357 self._arguments = arguments
358
359 def get_filters(self, until_position=None, origin_scope=None):
360 yield FunctionExecutionFilter(
361 self, self._value,
362 until_position=until_position,
363 origin_scope=origin_scope,
364 arguments=self._arguments
365 )
366
367 def infer_annotations(self):
368 from jedi.inference.gradual.annotation import infer_return_types
369 return infer_return_types(self._value, self._arguments)
370
371 def get_param_names(self):
372 return [
373 ParamName(self._value, param.name, self._arguments)
374 for param in self._value.tree_node.get_params()
375 ]
376
377
378class AnonymousFunctionExecution(BaseFunctionExecutionContext):
379 def infer_annotations(self):
380 # I don't think inferring anonymous executions is a big thing.
381 # Anonymous contexts are mostly there for the user to work in. ~ dave
382 return NO_VALUES
383
384 def get_filters(self, until_position=None, origin_scope=None):
385 yield AnonymousFunctionExecutionFilter(
386 self, self._value,
387 until_position=until_position,
388 origin_scope=origin_scope,
389 )
390
391 def get_param_names(self):
392 return self._value.get_param_names()
393
394
395class OverloadedFunctionValue(FunctionMixin, ValueWrapper):
396 def __init__(self, function, overloaded_functions):
397 super().__init__(function)
398 self._overloaded_functions = overloaded_functions
399
400 def py__call__(self, arguments):
401 debug.dbg("Execute overloaded function %s", self._wrapped_value, color='BLUE')
402 function_executions = []
403 for signature in self.get_signatures():
404 function_execution = signature.value.as_context(arguments)
405 function_executions.append(function_execution)
406 if signature.matches_signature(arguments):
407 return function_execution.infer()
408
409 if self.inference_state.is_analysis:
410 # In this case we want precision.
411 return NO_VALUES
412 return ValueSet.from_sets(fe.infer() for fe in function_executions)
413
414 def get_signature_functions(self):
415 return self._overloaded_functions
416
417 def get_type_hint(self, add_class_info=True):
418 return 'Union[%s]' % ', '.join(f.get_type_hint() for f in self._overloaded_functions)
419
420
421def _find_overload_functions(context, tree_node):
422 def _is_overload_decorated(funcdef):
423 if funcdef.parent.type == 'decorated':
424 decorators = funcdef.parent.children[0]
425 if decorators.type == 'decorator':
426 decorators = [decorators]
427 else:
428 decorators = decorators.children
429 for decorator in decorators:
430 dotted_name = decorator.children[1]
431 if dotted_name.type == 'name' and dotted_name.value == 'overload':
432 # TODO check with values if it's the right overload
433 return True
434 return False
435
436 if tree_node.type == 'lambdef':
437 return
438
439 if _is_overload_decorated(tree_node):
440 yield tree_node
441
442 while True:
443 filter = ParserTreeFilter(
444 context,
445 until_position=tree_node.start_pos
446 )
447 names = filter.get(tree_node.name.value)
448 assert isinstance(names, list)
449 if not names:
450 break
451
452 found = False
453 for name in names:
454 funcdef = name.tree_name.parent
455 if funcdef.type == 'funcdef' and _is_overload_decorated(funcdef):
456 tree_node = funcdef
457 found = True
458 yield funcdef
459
460 if not found:
461 break