Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/jedi/inference/base_value.py: 38%
333 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-20 06:09 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-20 06:09 +0000
1"""
2Values are the "values" that Python would return. However Values are at the
3same time also the "values" that a user is currently sitting in.
5A ValueSet is typically used to specify the return of a function or any other
6static analysis operation. In jedi there are always multiple returns and not
7just one.
8"""
9from functools import reduce
10from operator import add
11from itertools import zip_longest
13from parso.python.tree import Name
15from jedi import debug
16from jedi.parser_utils import clean_scope_docstring
17from jedi.inference.helpers import SimpleGetItemNotFound
18from jedi.inference.utils import safe_property
19from jedi.inference.cache import inference_state_as_method_param_cache
20from jedi.cache import memoize_method
22sentinel = object()
25class HasNoContext(Exception):
26 pass
29class HelperValueMixin:
30 def get_root_context(self):
31 value = self
32 if value.parent_context is None:
33 return value.as_context()
35 while True:
36 if value.parent_context is None:
37 return value
38 value = value.parent_context
40 def execute(self, arguments):
41 return self.inference_state.execute(self, arguments=arguments)
43 def execute_with_values(self, *value_list):
44 from jedi.inference.arguments import ValuesArguments
45 arguments = ValuesArguments([ValueSet([value]) for value in value_list])
46 return self.inference_state.execute(self, arguments)
48 def execute_annotation(self):
49 return self.execute_with_values()
51 def gather_annotation_classes(self):
52 return ValueSet([self])
54 def merge_types_of_iterate(self, contextualized_node=None, is_async=False):
55 return ValueSet.from_sets(
56 lazy_value.infer()
57 for lazy_value in self.iterate(contextualized_node, is_async)
58 )
60 def _get_value_filters(self, name_or_str):
61 origin_scope = name_or_str if isinstance(name_or_str, Name) else None
62 yield from self.get_filters(origin_scope=origin_scope)
63 # This covers the case where a stub files are incomplete.
64 if self.is_stub():
65 from jedi.inference.gradual.conversion import convert_values
66 for c in convert_values(ValueSet({self})):
67 yield from c.get_filters()
69 def goto(self, name_or_str, name_context=None, analysis_errors=True):
70 from jedi.inference import finder
71 filters = self._get_value_filters(name_or_str)
72 names = finder.filter_name(filters, name_or_str)
73 debug.dbg('context.goto %s in (%s): %s', name_or_str, self, names)
74 return names
76 def py__getattribute__(self, name_or_str, name_context=None, position=None,
77 analysis_errors=True):
78 """
79 :param position: Position of the last statement -> tuple of line, column
80 """
81 if name_context is None:
82 name_context = self
83 names = self.goto(name_or_str, name_context, analysis_errors)
84 values = ValueSet.from_sets(name.infer() for name in names)
85 if not values:
86 n = name_or_str.value if isinstance(name_or_str, Name) else name_or_str
87 values = self.py__getattribute__alternatives(n)
89 if not names and not values and analysis_errors:
90 if isinstance(name_or_str, Name):
91 from jedi.inference import analysis
92 analysis.add_attribute_error(
93 name_context, self, name_or_str)
94 debug.dbg('context.names_to_types: %s -> %s', names, values)
95 return values
97 def py__await__(self):
98 await_value_set = self.py__getattribute__("__await__")
99 if not await_value_set:
100 debug.warning('Tried to run __await__ on value %s', self)
101 return await_value_set.execute_with_values()
103 def py__name__(self):
104 return self.name.string_name
106 def iterate(self, contextualized_node=None, is_async=False):
107 debug.dbg('iterate %s', self)
108 if is_async:
109 from jedi.inference.lazy_value import LazyKnownValues
110 # TODO if no __aiter__ values are there, error should be:
111 # TypeError: 'async for' requires an object with __aiter__ method, got int
112 return iter([
113 LazyKnownValues(
114 self.py__getattribute__('__aiter__').execute_with_values()
115 .py__getattribute__('__anext__').execute_with_values()
116 .py__getattribute__('__await__').execute_with_values()
117 .py__stop_iteration_returns()
118 ) # noqa: E124
119 ])
120 return self.py__iter__(contextualized_node)
122 def is_sub_class_of(self, class_value):
123 with debug.increase_indent_cm('subclass matching of %s <=> %s' % (self, class_value),
124 color='BLUE'):
125 for cls in self.py__mro__():
126 if cls.is_same_class(class_value):
127 debug.dbg('matched subclass True', color='BLUE')
128 return True
129 debug.dbg('matched subclass False', color='BLUE')
130 return False
132 def is_same_class(self, class2):
133 # Class matching should prefer comparisons that are not this function.
134 if type(class2).is_same_class != HelperValueMixin.is_same_class:
135 return class2.is_same_class(self)
136 return self == class2
138 @memoize_method
139 def as_context(self, *args, **kwargs):
140 return self._as_context(*args, **kwargs)
143class Value(HelperValueMixin):
144 """
145 To be implemented by subclasses.
146 """
147 tree_node = None
148 # Possible values: None, tuple, list, dict and set. Here to deal with these
149 # very important containers.
150 array_type = None
151 api_type = 'not_defined_please_report_bug'
153 def __init__(self, inference_state, parent_context=None):
154 self.inference_state = inference_state
155 self.parent_context = parent_context
157 def py__getitem__(self, index_value_set, contextualized_node):
158 from jedi.inference import analysis
159 # TODO this value is probably not right.
160 analysis.add(
161 contextualized_node.context,
162 'type-error-not-subscriptable',
163 contextualized_node.node,
164 message="TypeError: '%s' object is not subscriptable" % self
165 )
166 return NO_VALUES
168 def py__simple_getitem__(self, index):
169 raise SimpleGetItemNotFound
171 def py__iter__(self, contextualized_node=None):
172 if contextualized_node is not None:
173 from jedi.inference import analysis
174 analysis.add(
175 contextualized_node.context,
176 'type-error-not-iterable',
177 contextualized_node.node,
178 message="TypeError: '%s' object is not iterable" % self)
179 return iter([])
181 def py__next__(self, contextualized_node=None):
182 return self.py__iter__(contextualized_node)
184 def get_signatures(self):
185 return []
187 def is_class(self):
188 return False
190 def is_class_mixin(self):
191 return False
193 def is_instance(self):
194 return False
196 def is_function(self):
197 return False
199 def is_module(self):
200 return False
202 def is_namespace(self):
203 return False
205 def is_compiled(self):
206 return False
208 def is_bound_method(self):
209 return False
211 def is_builtins_module(self):
212 return False
214 def py__bool__(self):
215 """
216 Since Wrapper is a super class for classes, functions and modules,
217 the return value will always be true.
218 """
219 return True
221 def py__doc__(self):
222 try:
223 self.tree_node.get_doc_node
224 except AttributeError:
225 return ''
226 else:
227 return clean_scope_docstring(self.tree_node)
229 def get_safe_value(self, default=sentinel):
230 if default is sentinel:
231 raise ValueError("There exists no safe value for value %s" % self)
232 return default
234 def execute_operation(self, other, operator):
235 debug.warning("%s not possible between %s and %s", operator, self, other)
236 return NO_VALUES
238 def py__call__(self, arguments):
239 debug.warning("no execution possible %s", self)
240 return NO_VALUES
242 def py__stop_iteration_returns(self):
243 debug.warning("Not possible to return the stop iterations of %s", self)
244 return NO_VALUES
246 def py__getattribute__alternatives(self, name_or_str):
247 """
248 For now a way to add values in cases like __getattr__.
249 """
250 return NO_VALUES
252 def py__get__(self, instance, class_value):
253 debug.warning("No __get__ defined on %s", self)
254 return ValueSet([self])
256 def py__get__on_class(self, calling_instance, instance, class_value):
257 return NotImplemented
259 def get_qualified_names(self):
260 # Returns Optional[Tuple[str, ...]]
261 return None
263 def is_stub(self):
264 # The root value knows if it's a stub or not.
265 return self.parent_context.is_stub()
267 def _as_context(self):
268 raise HasNoContext
270 @property
271 def name(self):
272 raise NotImplementedError
274 def get_type_hint(self, add_class_info=True):
275 return None
277 def infer_type_vars(self, value_set):
278 """
279 When the current instance represents a type annotation, this method
280 tries to find information about undefined type vars and returns a dict
281 from type var name to value set.
283 This is for example important to understand what `iter([1])` returns.
284 According to typeshed, `iter` returns an `Iterator[_T]`:
286 def iter(iterable: Iterable[_T]) -> Iterator[_T]: ...
288 This functions would generate `int` for `_T` in this case, because it
289 unpacks the `Iterable`.
291 Parameters
292 ----------
294 `self`: represents the annotation of the current parameter to infer the
295 value for. In the above example, this would initially be the
296 `Iterable[_T]` of the `iterable` parameter and then, when recursing,
297 just the `_T` generic parameter.
299 `value_set`: represents the actual argument passed to the parameter
300 we're inferred for, or (for recursive calls) their types. In the
301 above example this would first be the representation of the list
302 `[1]` and then, when recursing, just of `1`.
303 """
304 return {}
307def iterate_values(values, contextualized_node=None, is_async=False):
308 """
309 Calls `iterate`, on all values but ignores the ordering and just returns
310 all values that the iterate functions yield.
311 """
312 return ValueSet.from_sets(
313 lazy_value.infer()
314 for lazy_value in values.iterate(contextualized_node, is_async=is_async)
315 )
318class _ValueWrapperBase(HelperValueMixin):
319 @safe_property
320 def name(self):
321 from jedi.inference.names import ValueName
322 wrapped_name = self._wrapped_value.name
323 if wrapped_name.tree_name is not None:
324 return ValueName(self, wrapped_name.tree_name)
325 else:
326 from jedi.inference.compiled import CompiledValueName
327 return CompiledValueName(self, wrapped_name.string_name)
329 @classmethod
330 @inference_state_as_method_param_cache()
331 def create_cached(cls, inference_state, *args, **kwargs):
332 return cls(*args, **kwargs)
334 def __getattr__(self, name):
335 assert name != '_wrapped_value', 'Problem with _get_wrapped_value'
336 return getattr(self._wrapped_value, name)
339class LazyValueWrapper(_ValueWrapperBase):
340 @safe_property
341 @memoize_method
342 def _wrapped_value(self):
343 with debug.increase_indent_cm('Resolve lazy value wrapper'):
344 return self._get_wrapped_value()
346 def __repr__(self):
347 return '<%s>' % (self.__class__.__name__)
349 def _get_wrapped_value(self):
350 raise NotImplementedError
353class ValueWrapper(_ValueWrapperBase):
354 def __init__(self, wrapped_value):
355 self._wrapped_value = wrapped_value
357 def __repr__(self):
358 return '%s(%s)' % (self.__class__.__name__, self._wrapped_value)
361class TreeValue(Value):
362 def __init__(self, inference_state, parent_context, tree_node):
363 super().__init__(inference_state, parent_context)
364 self.tree_node = tree_node
366 def __repr__(self):
367 return '<%s: %s>' % (self.__class__.__name__, self.tree_node)
370class ContextualizedNode:
371 def __init__(self, context, node):
372 self.context = context
373 self.node = node
375 def get_root_context(self):
376 return self.context.get_root_context()
378 def infer(self):
379 return self.context.infer_node(self.node)
381 def __repr__(self):
382 return '<%s: %s in %s>' % (self.__class__.__name__, self.node, self.context)
385def _getitem(value, index_values, contextualized_node):
386 # The actual getitem call.
387 result = NO_VALUES
388 unused_values = set()
389 for index_value in index_values:
390 index = index_value.get_safe_value(default=None)
391 if type(index) in (float, int, str, slice, bytes):
392 try:
393 result |= value.py__simple_getitem__(index)
394 continue
395 except SimpleGetItemNotFound:
396 pass
398 unused_values.add(index_value)
400 # The index was somehow not good enough or simply a wrong type.
401 # Therefore we now iterate through all the values and just take
402 # all results.
403 if unused_values or not index_values:
404 result |= value.py__getitem__(
405 ValueSet(unused_values),
406 contextualized_node
407 )
408 debug.dbg('py__getitem__ result: %s', result)
409 return result
412class ValueSet:
413 def __init__(self, iterable):
414 self._set = frozenset(iterable)
415 for value in iterable:
416 assert not isinstance(value, ValueSet)
418 @classmethod
419 def _from_frozen_set(cls, frozenset_):
420 self = cls.__new__(cls)
421 self._set = frozenset_
422 return self
424 @classmethod
425 def from_sets(cls, sets):
426 """
427 Used to work with an iterable of set.
428 """
429 aggregated = set()
430 for set_ in sets:
431 if isinstance(set_, ValueSet):
432 aggregated |= set_._set
433 else:
434 aggregated |= frozenset(set_)
435 return cls._from_frozen_set(frozenset(aggregated))
437 def __or__(self, other):
438 return self._from_frozen_set(self._set | other._set)
440 def __and__(self, other):
441 return self._from_frozen_set(self._set & other._set)
443 def __iter__(self):
444 return iter(self._set)
446 def __bool__(self):
447 return bool(self._set)
449 def __len__(self):
450 return len(self._set)
452 def __repr__(self):
453 return 'S{%s}' % (', '.join(str(s) for s in self._set))
455 def filter(self, filter_func):
456 return self.__class__(filter(filter_func, self._set))
458 def __getattr__(self, name):
459 def mapper(*args, **kwargs):
460 return self.from_sets(
461 getattr(value, name)(*args, **kwargs)
462 for value in self._set
463 )
464 return mapper
466 def __eq__(self, other):
467 return self._set == other._set
469 def __ne__(self, other):
470 return not self.__eq__(other)
472 def __hash__(self):
473 return hash(self._set)
475 def py__class__(self):
476 return ValueSet(c.py__class__() for c in self._set)
478 def iterate(self, contextualized_node=None, is_async=False):
479 from jedi.inference.lazy_value import get_merged_lazy_value
480 type_iters = [c.iterate(contextualized_node, is_async=is_async) for c in self._set]
481 for lazy_values in zip_longest(*type_iters):
482 yield get_merged_lazy_value(
483 [l for l in lazy_values if l is not None]
484 )
486 def execute(self, arguments):
487 return ValueSet.from_sets(c.inference_state.execute(c, arguments) for c in self._set)
489 def execute_with_values(self, *args, **kwargs):
490 return ValueSet.from_sets(c.execute_with_values(*args, **kwargs) for c in self._set)
492 def goto(self, *args, **kwargs):
493 return reduce(add, [c.goto(*args, **kwargs) for c in self._set], [])
495 def py__getattribute__(self, *args, **kwargs):
496 return ValueSet.from_sets(c.py__getattribute__(*args, **kwargs) for c in self._set)
498 def get_item(self, *args, **kwargs):
499 return ValueSet.from_sets(_getitem(c, *args, **kwargs) for c in self._set)
501 def try_merge(self, function_name):
502 value_set = self.__class__([])
503 for c in self._set:
504 try:
505 method = getattr(c, function_name)
506 except AttributeError:
507 pass
508 else:
509 value_set |= method()
510 return value_set
512 def gather_annotation_classes(self):
513 return ValueSet.from_sets([c.gather_annotation_classes() for c in self._set])
515 def get_signatures(self):
516 return [sig for c in self._set for sig in c.get_signatures()]
518 def get_type_hint(self, add_class_info=True):
519 t = [v.get_type_hint(add_class_info=add_class_info) for v in self._set]
520 type_hints = sorted(filter(None, t))
521 if len(type_hints) == 1:
522 return type_hints[0]
524 optional = 'None' in type_hints
525 if optional:
526 type_hints.remove('None')
528 if len(type_hints) == 0:
529 return None
530 elif len(type_hints) == 1:
531 s = type_hints[0]
532 else:
533 s = 'Union[%s]' % ', '.join(type_hints)
534 if optional:
535 s = 'Optional[%s]' % s
536 return s
538 def infer_type_vars(self, value_set):
539 # Circular
540 from jedi.inference.gradual.annotation import merge_type_var_dicts
542 type_var_dict = {}
543 for value in self._set:
544 merge_type_var_dicts(
545 type_var_dict,
546 value.infer_type_vars(value_set),
547 )
548 return type_var_dict
551NO_VALUES = ValueSet([])
554def iterator_to_value_set(func):
555 def wrapper(*args, **kwargs):
556 return ValueSet(func(*args, **kwargs))
558 return wrapper