Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/jedi/inference/compiled/value.py: 33%
384 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-26 06:07 +0000
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-26 06:07 +0000
1"""
2Imitate the parser representation.
3"""
4import re
5from functools import partial
6from inspect import Parameter
7from pathlib import Path
8from typing import Optional
10from jedi import debug
11from jedi.inference.utils import to_list
12from jedi.cache import memoize_method
13from jedi.inference.filters import AbstractFilter
14from jedi.inference.names import AbstractNameDefinition, ValueNameMixin, \
15 ParamNameInterface
16from jedi.inference.base_value import Value, ValueSet, NO_VALUES
17from jedi.inference.lazy_value import LazyKnownValue
18from jedi.inference.compiled.access import _sentinel
19from jedi.inference.cache import inference_state_function_cache
20from jedi.inference.helpers import reraise_getitem_errors
21from jedi.inference.signature import BuiltinSignature
22from jedi.inference.context import CompiledContext, CompiledModuleContext
25class CheckAttribute:
26 """Raises :exc:`AttributeError` if the attribute X is not available."""
27 def __init__(self, check_name=None):
28 # Remove the py in front of e.g. py__call__.
29 self.check_name = check_name
31 def __call__(self, func):
32 self.func = func
33 if self.check_name is None:
34 self.check_name = func.__name__[2:]
35 return self
37 def __get__(self, instance, owner):
38 if instance is None:
39 return self
41 # This might raise an AttributeError. That's wanted.
42 instance.access_handle.getattr_paths(self.check_name)
43 return partial(self.func, instance)
46class CompiledValue(Value):
47 def __init__(self, inference_state, access_handle, parent_context=None):
48 super().__init__(inference_state, parent_context)
49 self.access_handle = access_handle
51 def py__call__(self, arguments):
52 return_annotation = self.access_handle.get_return_annotation()
53 if return_annotation is not None:
54 # TODO the return annotation may also be a string.
55 return create_from_access_path(
56 self.inference_state,
57 return_annotation
58 ).execute_annotation()
60 try:
61 self.access_handle.getattr_paths('__call__')
62 except AttributeError:
63 return super().py__call__(arguments)
64 else:
65 if self.access_handle.is_class():
66 from jedi.inference.value import CompiledInstance
67 return ValueSet([
68 CompiledInstance(self.inference_state, self.parent_context, self, arguments)
69 ])
70 else:
71 return ValueSet(self._execute_function(arguments))
73 @CheckAttribute()
74 def py__class__(self):
75 return create_from_access_path(self.inference_state, self.access_handle.py__class__())
77 @CheckAttribute()
78 def py__mro__(self):
79 return (self,) + tuple(
80 create_from_access_path(self.inference_state, access)
81 for access in self.access_handle.py__mro__accesses()
82 )
84 @CheckAttribute()
85 def py__bases__(self):
86 return tuple(
87 create_from_access_path(self.inference_state, access)
88 for access in self.access_handle.py__bases__()
89 )
91 def get_qualified_names(self):
92 return self.access_handle.get_qualified_names()
94 def py__bool__(self):
95 return self.access_handle.py__bool__()
97 def is_class(self):
98 return self.access_handle.is_class()
100 def is_function(self):
101 return self.access_handle.is_function()
103 def is_module(self):
104 return self.access_handle.is_module()
106 def is_compiled(self):
107 return True
109 def is_stub(self):
110 return False
112 def is_instance(self):
113 return self.access_handle.is_instance()
115 def py__doc__(self):
116 return self.access_handle.py__doc__()
118 @to_list
119 def get_param_names(self):
120 try:
121 signature_params = self.access_handle.get_signature_params()
122 except ValueError: # Has no signature
123 params_str, ret = self._parse_function_doc()
124 if not params_str:
125 tokens = []
126 else:
127 tokens = params_str.split(',')
128 if self.access_handle.ismethoddescriptor():
129 tokens.insert(0, 'self')
130 for p in tokens:
131 name, _, default = p.strip().partition('=')
132 yield UnresolvableParamName(self, name, default)
133 else:
134 for signature_param in signature_params:
135 yield SignatureParamName(self, signature_param)
137 def get_signatures(self):
138 _, return_string = self._parse_function_doc()
139 return [BuiltinSignature(self, return_string)]
141 def __repr__(self):
142 return '<%s: %s>' % (self.__class__.__name__, self.access_handle.get_repr())
144 @memoize_method
145 def _parse_function_doc(self):
146 doc = self.py__doc__()
147 if doc is None:
148 return '', ''
150 return _parse_function_doc(doc)
152 @property
153 def api_type(self):
154 return self.access_handle.get_api_type()
156 def get_filters(self, is_instance=False, origin_scope=None):
157 yield self._ensure_one_filter(is_instance)
159 @memoize_method
160 def _ensure_one_filter(self, is_instance):
161 return CompiledValueFilter(self.inference_state, self, is_instance)
163 def py__simple_getitem__(self, index):
164 with reraise_getitem_errors(IndexError, KeyError, TypeError):
165 try:
166 access = self.access_handle.py__simple_getitem__(index)
167 except AttributeError:
168 return super().py__simple_getitem__(index)
169 if access is None:
170 return super().py__simple_getitem__(index)
172 return ValueSet([create_from_access_path(self.inference_state, access)])
174 def py__getitem__(self, index_value_set, contextualized_node):
175 all_access_paths = self.access_handle.py__getitem__all_values()
176 if all_access_paths is None:
177 # This means basically that no __getitem__ has been defined on this
178 # object.
179 return super().py__getitem__(index_value_set, contextualized_node)
180 return ValueSet(
181 create_from_access_path(self.inference_state, access)
182 for access in all_access_paths
183 )
185 def py__iter__(self, contextualized_node=None):
186 if not self.access_handle.has_iter():
187 yield from super().py__iter__(contextualized_node)
189 access_path_list = self.access_handle.py__iter__list()
190 if access_path_list is None:
191 # There is no __iter__ method on this object.
192 return
194 for access in access_path_list:
195 yield LazyKnownValue(create_from_access_path(self.inference_state, access))
197 def py__name__(self):
198 return self.access_handle.py__name__()
200 @property
201 def name(self):
202 name = self.py__name__()
203 if name is None:
204 name = self.access_handle.get_repr()
205 return CompiledValueName(self, name)
207 def _execute_function(self, params):
208 from jedi.inference import docstrings
209 from jedi.inference.compiled import builtin_from_name
210 if self.api_type != 'function':
211 return
213 for name in self._parse_function_doc()[1].split():
214 try:
215 # TODO wtf is this? this is exactly the same as the thing
216 # below. It uses getattr as well.
217 self.inference_state.builtins_module.access_handle.getattr_paths(name)
218 except AttributeError:
219 continue
220 else:
221 bltn_obj = builtin_from_name(self.inference_state, name)
222 yield from self.inference_state.execute(bltn_obj, params)
223 yield from docstrings.infer_return_types(self)
225 def get_safe_value(self, default=_sentinel):
226 try:
227 return self.access_handle.get_safe_value()
228 except ValueError:
229 if default == _sentinel:
230 raise
231 return default
233 def execute_operation(self, other, operator):
234 try:
235 return ValueSet([create_from_access_path(
236 self.inference_state,
237 self.access_handle.execute_operation(other.access_handle, operator)
238 )])
239 except TypeError:
240 return NO_VALUES
242 def execute_annotation(self):
243 if self.access_handle.get_repr() == 'None':
244 # None as an annotation doesn't need to be executed.
245 return ValueSet([self])
247 name, args = self.access_handle.get_annotation_name_and_args()
248 arguments = [
249 ValueSet([create_from_access_path(self.inference_state, path)])
250 for path in args
251 ]
252 if name == 'Union':
253 return ValueSet.from_sets(arg.execute_annotation() for arg in arguments)
254 elif name:
255 # While with_generics only exists on very specific objects, we
256 # should probably be fine, because we control all the typing
257 # objects.
258 return ValueSet([
259 v.with_generics(arguments)
260 for v in self.inference_state.typing_module.py__getattribute__(name)
261 ]).execute_annotation()
262 return super().execute_annotation()
264 def negate(self):
265 return create_from_access_path(self.inference_state, self.access_handle.negate())
267 def get_metaclasses(self):
268 return NO_VALUES
270 def _as_context(self):
271 return CompiledContext(self)
273 @property
274 def array_type(self):
275 return self.access_handle.get_array_type()
277 def get_key_values(self):
278 return [
279 create_from_access_path(self.inference_state, k)
280 for k in self.access_handle.get_key_paths()
281 ]
283 def get_type_hint(self, add_class_info=True):
284 if self.access_handle.get_repr() in ('None', "<class 'NoneType'>"):
285 return 'None'
286 return None
289class CompiledModule(CompiledValue):
290 file_io = None # For modules
292 def _as_context(self):
293 return CompiledModuleContext(self)
295 def py__path__(self):
296 return self.access_handle.py__path__()
298 def is_package(self):
299 return self.py__path__() is not None
301 @property
302 def string_names(self):
303 # For modules
304 name = self.py__name__()
305 if name is None:
306 return ()
307 return tuple(name.split('.'))
309 def py__file__(self) -> Optional[Path]:
310 return self.access_handle.py__file__() # type: ignore[no-any-return]
313class CompiledName(AbstractNameDefinition):
314 def __init__(self, inference_state, parent_value, name):
315 self._inference_state = inference_state
316 self.parent_context = parent_value.as_context()
317 self._parent_value = parent_value
318 self.string_name = name
320 def py__doc__(self):
321 return self.infer_compiled_value().py__doc__()
323 def _get_qualified_names(self):
324 parent_qualified_names = self.parent_context.get_qualified_names()
325 if parent_qualified_names is None:
326 return None
327 return parent_qualified_names + (self.string_name,)
329 def get_defining_qualified_value(self):
330 context = self.parent_context
331 if context.is_module() or context.is_class():
332 return self.parent_context.get_value() # Might be None
334 return None
336 def __repr__(self):
337 try:
338 name = self.parent_context.name # __name__ is not defined all the time
339 except AttributeError:
340 name = None
341 return '<%s: (%s).%s>' % (self.__class__.__name__, name, self.string_name)
343 @property
344 def api_type(self):
345 return self.infer_compiled_value().api_type
347 def infer(self):
348 return ValueSet([self.infer_compiled_value()])
350 @memoize_method
351 def infer_compiled_value(self):
352 return create_from_name(self._inference_state, self._parent_value, self.string_name)
355class SignatureParamName(ParamNameInterface, AbstractNameDefinition):
356 def __init__(self, compiled_value, signature_param):
357 self.parent_context = compiled_value.parent_context
358 self._signature_param = signature_param
360 @property
361 def string_name(self):
362 return self._signature_param.name
364 def to_string(self):
365 s = self._kind_string() + self.string_name
366 if self._signature_param.has_annotation:
367 s += ': ' + self._signature_param.annotation_string
368 if self._signature_param.has_default:
369 s += '=' + self._signature_param.default_string
370 return s
372 def get_kind(self):
373 return getattr(Parameter, self._signature_param.kind_name)
375 def infer(self):
376 p = self._signature_param
377 inference_state = self.parent_context.inference_state
378 values = NO_VALUES
379 if p.has_default:
380 values = ValueSet([create_from_access_path(inference_state, p.default)])
381 if p.has_annotation:
382 annotation = create_from_access_path(inference_state, p.annotation)
383 values |= annotation.execute_with_values()
384 return values
387class UnresolvableParamName(ParamNameInterface, AbstractNameDefinition):
388 def __init__(self, compiled_value, name, default):
389 self.parent_context = compiled_value.parent_context
390 self.string_name = name
391 self._default = default
393 def get_kind(self):
394 return Parameter.POSITIONAL_ONLY
396 def to_string(self):
397 string = self.string_name
398 if self._default:
399 string += '=' + self._default
400 return string
402 def infer(self):
403 return NO_VALUES
406class CompiledValueName(ValueNameMixin, AbstractNameDefinition):
407 def __init__(self, value, name):
408 self.string_name = name
409 self._value = value
410 self.parent_context = value.parent_context
413class EmptyCompiledName(AbstractNameDefinition):
414 """
415 Accessing some names will raise an exception. To avoid not having any
416 completions, just give Jedi the option to return this object. It infers to
417 nothing.
418 """
419 def __init__(self, inference_state, name):
420 self.parent_context = inference_state.builtins_module
421 self.string_name = name
423 def infer(self):
424 return NO_VALUES
427class CompiledValueFilter(AbstractFilter):
428 def __init__(self, inference_state, compiled_value, is_instance=False):
429 self._inference_state = inference_state
430 self.compiled_value = compiled_value
431 self.is_instance = is_instance
433 def get(self, name):
434 access_handle = self.compiled_value.access_handle
435 return self._get(
436 name,
437 lambda name, safe: access_handle.is_allowed_getattr(name, safe=safe),
438 lambda name: name in access_handle.dir(),
439 check_has_attribute=True
440 )
442 def _get(self, name, allowed_getattr_callback, in_dir_callback, check_has_attribute=False):
443 """
444 To remove quite a few access calls we introduced the callback here.
445 """
446 if self._inference_state.allow_descriptor_getattr:
447 pass
449 has_attribute, is_descriptor = allowed_getattr_callback(
450 name,
451 safe=not self._inference_state.allow_descriptor_getattr
452 )
453 if check_has_attribute and not has_attribute:
454 return []
456 if (is_descriptor or not has_attribute) \
457 and not self._inference_state.allow_descriptor_getattr:
458 return [self._get_cached_name(name, is_empty=True)]
460 if self.is_instance and not in_dir_callback(name):
461 return []
462 return [self._get_cached_name(name)]
464 @memoize_method
465 def _get_cached_name(self, name, is_empty=False):
466 if is_empty:
467 return EmptyCompiledName(self._inference_state, name)
468 else:
469 return self._create_name(name)
471 def values(self):
472 from jedi.inference.compiled import builtin_from_name
473 names = []
474 needs_type_completions, dir_infos = self.compiled_value.access_handle.get_dir_infos()
475 # We could use `safe=False` here as well, especially as a parameter to
476 # get_dir_infos. But this would lead to a lot of property executions
477 # that are probably not wanted. The drawback for this is that we
478 # have a different name for `get` and `values`. For `get` we always
479 # execute.
480 for name in dir_infos:
481 names += self._get(
482 name,
483 lambda name, safe: dir_infos[name],
484 lambda name: name in dir_infos,
485 )
487 # ``dir`` doesn't include the type names.
488 if not self.is_instance and needs_type_completions:
489 for filter in builtin_from_name(self._inference_state, 'type').get_filters():
490 names += filter.values()
491 return names
493 def _create_name(self, name):
494 return CompiledName(
495 self._inference_state,
496 self.compiled_value,
497 name
498 )
500 def __repr__(self):
501 return "<%s: %s>" % (self.__class__.__name__, self.compiled_value)
504docstr_defaults = {
505 'floating point number': 'float',
506 'character': 'str',
507 'integer': 'int',
508 'dictionary': 'dict',
509 'string': 'str',
510}
513def _parse_function_doc(doc):
514 """
515 Takes a function and returns the params and return value as a tuple.
516 This is nothing more than a docstring parser.
518 TODO docstrings like utime(path, (atime, mtime)) and a(b [, b]) -> None
519 TODO docstrings like 'tuple of integers'
520 """
521 # parse round parentheses: def func(a, (b,c))
522 try:
523 count = 0
524 start = doc.index('(')
525 for i, s in enumerate(doc[start:]):
526 if s == '(':
527 count += 1
528 elif s == ')':
529 count -= 1
530 if count == 0:
531 end = start + i
532 break
533 param_str = doc[start + 1:end]
534 except (ValueError, UnboundLocalError):
535 # ValueError for doc.index
536 # UnboundLocalError for undefined end in last line
537 debug.dbg('no brackets found - no param')
538 end = 0
539 param_str = ''
540 else:
541 # remove square brackets, that show an optional param ( = None)
542 def change_options(m):
543 args = m.group(1).split(',')
544 for i, a in enumerate(args):
545 if a and '=' not in a:
546 args[i] += '=None'
547 return ','.join(args)
549 while True:
550 param_str, changes = re.subn(r' ?\[([^\[\]]+)\]',
551 change_options, param_str)
552 if changes == 0:
553 break
554 param_str = param_str.replace('-', '_') # see: isinstance.__doc__
556 # parse return value
557 r = re.search('-[>-]* ', doc[end:end + 7])
558 if r is None:
559 ret = ''
560 else:
561 index = end + r.end()
562 # get result type, which can contain newlines
563 pattern = re.compile(r'(,\n|[^\n-])+')
564 ret_str = pattern.match(doc, index).group(0).strip()
565 # New object -> object()
566 ret_str = re.sub(r'[nN]ew (.*)', r'\1()', ret_str)
568 ret = docstr_defaults.get(ret_str, ret_str)
570 return param_str, ret
573def create_from_name(inference_state, compiled_value, name):
574 access_paths = compiled_value.access_handle.getattr_paths(name, default=None)
576 value = None
577 for access_path in access_paths:
578 value = create_cached_compiled_value(
579 inference_state,
580 access_path,
581 parent_context=None if value is None else value.as_context(),
582 )
583 return value
586def _normalize_create_args(func):
587 """The cache doesn't care about keyword vs. normal args."""
588 def wrapper(inference_state, obj, parent_context=None):
589 return func(inference_state, obj, parent_context)
590 return wrapper
593def create_from_access_path(inference_state, access_path):
594 value = None
595 for name, access in access_path.accesses:
596 value = create_cached_compiled_value(
597 inference_state,
598 access,
599 parent_context=None if value is None else value.as_context()
600 )
601 return value
604@_normalize_create_args
605@inference_state_function_cache()
606def create_cached_compiled_value(inference_state, access_handle, parent_context):
607 assert not isinstance(parent_context, CompiledValue)
608 if parent_context is None:
609 cls = CompiledModule
610 else:
611 cls = CompiledValue
612 return cls(inference_state, access_handle, parent_context)