1 from parso
.python
import tree
4 from jedi
.inference
.cache
import inference_state_method_cache
, CachedMetaClass
5 from jedi
.inference
import compiled
6 from jedi
.inference
import recursion
7 from jedi
.inference
import docstrings
8 from jedi
.inference
import flow_analysis
9 from jedi
.inference
.signature
import TreeSignature
10 from jedi
.inference
.filters
import ParserTreeFilter
, FunctionExecutionFilter
, \
11 AnonymousFunctionExecutionFilter
12 from jedi
.inference
.names
import ValueName
, AbstractNameDefinition
, \
13 AnonymousParamName
, ParamName
, NameWrapper
14 from jedi
.inference
.base_value
import ContextualizedNode
, NO_VALUES
, \
15 ValueSet
, TreeValue
, ValueWrapper
16 from jedi
.inference
.lazy_value
import LazyKnownValues
, LazyKnownValue
, \
18 from jedi
.inference
.context
import ValueContext
, TreeContextMixin
19 from jedi
.inference
.value
import iterable
20 from jedi
import parser_utils
21 from jedi
.inference
.parser_cache
import get_yield_exprs
22 from jedi
.inference
.helpers
import values_from_qualified_names
23 from jedi
.inference
.gradual
.generics
import TupleGenericManager
26 class LambdaName(AbstractNameDefinition
):
27 string_name
= '<lambda>'
30 def __init__(self
, lambda_value
):
31 self
._lambda
_value
= lambda_value
32 self
.parent_context
= lambda_value
.parent_context
36 return self
._lambda
_value
.tree_node
.start_pos
39 return ValueSet([self
._lambda
_value
])
42 class FunctionAndClassBase(TreeValue
):
43 def get_qualified_names(self
):
44 if self
.parent_context
.is_class():
45 n
= self
.parent_context
.get_qualified_names()
47 # This means that the parent class lives within a function.
49 return n
+ (self
.py__name__(),)
50 elif self
.parent_context
.is_module():
51 return (self
.py__name__(),)
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
)
64 def py__get__(self
, instance
, class_value
):
65 from jedi
.inference
.value
.instance
import BoundMethod
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
)])
71 def get_param_names(self
):
72 return [AnonymousParamName(self
, param
.name
)
73 for param
in self
.tree_node
.get_params()]
77 if self
.tree_node
.type == 'lambdef':
78 return LambdaName(self
)
79 return ValueName(self
, self
.tree_node
.name
)
81 def is_function(self
):
85 return self
.name
.string_name
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
):
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)
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([
104 for n
in function_execution
.get_param_names()
106 if return_hint
is None:
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)
112 return body
+ ' -> ' + return_hint
114 def py__call__(self
, arguments
):
115 function_execution
= self
.as_context(arguments
)
116 return function_execution
.infer()
118 def _as_context(self
, arguments
=None):
119 if arguments
is None:
120 return AnonymousFunctionExecution(self
)
121 return FunctionExecutionContext(self
, arguments
)
123 def get_signatures(self
):
124 return [TreeSignature(f
) for f
in self
.get_signature_functions()]
127 class FunctionValue(FunctionMixin
, FunctionAndClassBase
, metaclass
=CachedMetaClass
):
129 def from_context(cls
, context
, tree_node
):
130 def create(tree_node
):
131 if context
.is_class():
133 context
.inference_state
,
135 parent_context
=parent_context
,
140 context
.inference_state
,
141 parent_context
=parent_context
,
145 overloaded_funcs
= list(_find_overload_functions(context
, tree_node
))
147 parent_context
= context
148 while parent_context
.is_class() or parent_context
.is_instance():
149 parent_context
= parent_context
.parent_context
151 function
= create(tree_node
)
154 return OverloadedFunctionValue(
156 # Get them into the correct order: lower line first.
157 list(reversed([create(f
) for f
in overloaded_funcs
]))
161 def py__class__(self
):
162 c
, = values_from_qualified_names(self
.inference_state
, 'types', 'FunctionType')
165 def get_default_param_context(self
):
166 return self
.parent_context
168 def get_signature_functions(self
):
172 class FunctionNameInClass(NameWrapper
):
173 def __init__(self
, class_context
, name
):
174 super().__init
__(name
)
175 self
._class
_context
= class_context
177 def get_defining_qualified_value(self
):
178 return self
._class
_context
.get_value() # Might be None.
181 class 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
186 def get_default_param_context(self
):
187 return self
.class_context
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()
195 return names
+ (self
.py__name__(),)
199 return FunctionNameInClass(self
.class_context
, super().name
)
202 class BaseFunctionExecutionContext(ValueContext
, TreeContextMixin
):
203 def infer_annotations(self
):
204 raise NotImplementedError
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])
214 value_set
= NO_VALUES
215 returns
= get_yield_exprs(self
.inference_state
, funcdef
)
217 value_set
= self
.infer_annotations()
219 # If there are annotations, prefer them over anything else.
220 # This will make it faster.
222 value_set |
= docstrings
.infer_return_types(self
._value
)
223 returns
= funcdef
.iter_return_stmts()
227 value_set |
= ValueSet
.from_sets(
229 for lazy_value
in self
._get
_yield
_lazy
_value
(r
)
232 check
= flow_analysis
.reachability_check(self
, funcdef
, r
)
233 if check
is flow_analysis
.UNREACHABLE
:
234 debug
.dbg('Return unreachable: %s', r
)
237 children
= r
.children
238 except AttributeError:
239 ctx
= compiled
.builtin_from_name(self
.inference_state
, 'None')
240 value_set |
= ValueSet([ctx
])
242 value_set |
= self
.infer_node(children
[1])
243 if check
is flow_analysis
.REACHABLE
:
244 debug
.dbg('Return reachable: %s', r
)
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
)
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
)
260 yield LazyTreeValue(self
, node
)
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
)]
269 # Calculate if the yields are placed within the same for loop.
272 for yield_
, for_stmt
in for_parents
:
273 # For really simple for loops we can predict the order. Otherwise
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_
)
283 yields_order
.append((for_stmt
, [yield_
]))
284 elif for_stmt
== self
.tree_node
:
285 yields_order
.append((None, [yield_
]))
287 types
= self
.get_return_values(check_yields
=True)
289 yield LazyKnownValues(types
, min=0, max=float('inf'))
291 last_for_stmt
= for_stmt
293 for for_stmt
, yields
in yields_order
:
295 # No for_stmt, just normal yields.
296 for yield_
in yields
:
297 yield from self
._get
_yield
_lazy
_value
(yield_
)
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
)
309 def merge_yield_values(self
, is_async
=False):
310 return ValueSet
.from_sets(
312 for lazy_value
in self
.get_yield_lazy_values()
315 def is_generator(self
):
316 return bool(get_yield_exprs(self
.inference_state
, self
.tree_node
))
320 Created to be used by inheritance.
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
327 if self
.is_generator():
328 async_generator_classes
= inference_state
.typing_module \
329 .py__getattribute__('AsyncGenerator')
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
)
335 GenericClass(c
, TupleGenericManager(generics
))
336 for c
in async_generator_classes
337 ).execute_annotation()
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
)
344 GenericClass(c
, TupleGenericManager(generics
)) for c
in async_classes
345 ).execute_annotation()
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
)])
351 return self
.get_return_values()
354 class FunctionExecutionContext(BaseFunctionExecutionContext
):
355 def __init__(self
, function_value
, arguments
):
356 super().__init
__(function_value
)
357 self
._arguments
= arguments
359 def get_filters(self
, until_position
=None, origin_scope
=None):
360 yield FunctionExecutionFilter(
362 until_position
=until_position
,
363 origin_scope
=origin_scope
,
364 arguments
=self
._arguments
367 def infer_annotations(self
):
368 from jedi
.inference
.gradual
.annotation
import infer_return_types
369 return infer_return_types(self
._value
, self
._arguments
)
371 def get_param_names(self
):
373 ParamName(self
._value
, param
.name
, self
._arguments
)
374 for param
in self
._value
.tree_node
.get_params()
378 class 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
384 def get_filters(self
, until_position
=None, origin_scope
=None):
385 yield AnonymousFunctionExecutionFilter(
387 until_position
=until_position
,
388 origin_scope
=origin_scope
,
391 def get_param_names(self
):
392 return self
._value
.get_param_names()
395 class OverloadedFunctionValue(FunctionMixin
, ValueWrapper
):
396 def __init__(self
, function
, overloaded_functions
):
397 super().__init
__(function
)
398 self
._overloaded
_functions
= overloaded_functions
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()
409 if self
.inference_state
.is_analysis
:
410 # In this case we want precision.
412 return ValueSet
.from_sets(fe
.infer() for fe
in function_executions
)
414 def get_signature_functions(self
):
415 return self
._overloaded
_functions
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
)
421 def _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
]
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
436 if tree_node
.type == 'lambdef':
439 if _is_overload_decorated(tree_node
):
443 filter = ParserTreeFilter(
445 until_position
=tree_node
.start_pos
447 names
= filter.get(tree_node
.name
.value
)
448 assert isinstance(names
, list)
454 funcdef
= name
.tree_name
.parent
455 if funcdef
.type == 'funcdef' and _is_overload_decorated(funcdef
):