| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610 |
- from abc import abstractproperty
- from parso.tree import search_ancestor
- from jedi import debug
- from jedi import settings
- from jedi.inference import compiled
- from jedi.inference.compiled.value import CompiledValueFilter
- from jedi.inference.helpers import values_from_qualified_names, is_big_annoying_library
- from jedi.inference.filters import AbstractFilter, AnonymousFunctionExecutionFilter
- from jedi.inference.names import ValueName, TreeNameDefinition, ParamName, \
- NameWrapper
- from jedi.inference.base_value import Value, NO_VALUES, ValueSet, \
- iterator_to_value_set, ValueWrapper
- from jedi.inference.lazy_value import LazyKnownValue, LazyKnownValues
- from jedi.inference.cache import inference_state_method_cache
- from jedi.inference.arguments import ValuesArguments, TreeArgumentsWrapper
- from jedi.inference.value.function import \
- FunctionValue, FunctionMixin, OverloadedFunctionValue, \
- BaseFunctionExecutionContext, FunctionExecutionContext, FunctionNameInClass
- from jedi.inference.value.klass import ClassFilter
- from jedi.inference.value.dynamic_arrays import get_dynamic_array_instance
- from jedi.parser_utils import function_is_staticmethod, function_is_classmethod
- class InstanceExecutedParamName(ParamName):
- def __init__(self, instance, function_value, tree_name):
- super().__init__(
- function_value, tree_name, arguments=None)
- self._instance = instance
- def infer(self):
- return ValueSet([self._instance])
- def matches_signature(self):
- return True
- class AnonymousMethodExecutionFilter(AnonymousFunctionExecutionFilter):
- def __init__(self, instance, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self._instance = instance
- def _convert_param(self, param, name):
- if param.position_index == 0:
- if function_is_classmethod(self._function_value.tree_node):
- return InstanceExecutedParamName(
- self._instance.py__class__(),
- self._function_value,
- name
- )
- elif not function_is_staticmethod(self._function_value.tree_node):
- return InstanceExecutedParamName(
- self._instance,
- self._function_value,
- name
- )
- return super()._convert_param(param, name)
- class AnonymousMethodExecutionContext(BaseFunctionExecutionContext):
- def __init__(self, instance, value):
- super().__init__(value)
- self.instance = instance
- def get_filters(self, until_position=None, origin_scope=None):
- yield AnonymousMethodExecutionFilter(
- self.instance, self, self._value,
- until_position=until_position,
- origin_scope=origin_scope,
- )
- def get_param_names(self):
- param_names = list(self._value.get_param_names())
- # set the self name
- param_names[0] = InstanceExecutedParamName(
- self.instance,
- self._value,
- param_names[0].tree_name
- )
- return param_names
- class MethodExecutionContext(FunctionExecutionContext):
- def __init__(self, instance, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.instance = instance
- class AbstractInstanceValue(Value):
- api_type = 'instance'
- def __init__(self, inference_state, parent_context, class_value):
- super().__init__(inference_state, parent_context)
- # Generated instances are classes that are just generated by self
- # (No arguments) used.
- self.class_value = class_value
- def is_instance(self):
- return True
- def get_qualified_names(self):
- return self.class_value.get_qualified_names()
- def get_annotated_class_object(self):
- return self.class_value # This is the default.
- def py__class__(self):
- return self.class_value
- def py__bool__(self):
- # Signalize that we don't know about the bool type.
- return None
- @abstractproperty
- def name(self):
- raise NotImplementedError
- def get_signatures(self):
- call_funcs = self.py__getattribute__('__call__').py__get__(self, self.class_value)
- return [s.bind(self) for s in call_funcs.get_signatures()]
- def get_function_slot_names(self, name):
- # Python classes don't look at the dictionary of the instance when
- # looking up `__call__`. This is something that has to do with Python's
- # internal slot system (note: not __slots__, but C slots).
- for filter in self.get_filters(include_self_names=False):
- names = filter.get(name)
- if names:
- return names
- return []
- def execute_function_slots(self, names, *inferred_args):
- return ValueSet.from_sets(
- name.infer().execute_with_values(*inferred_args)
- for name in names
- )
- def get_type_hint(self, add_class_info=True):
- return self.py__name__()
- def py__getitem__(self, index_value_set, contextualized_node):
- names = self.get_function_slot_names('__getitem__')
- if not names:
- return super().py__getitem__(
- index_value_set,
- contextualized_node,
- )
- args = ValuesArguments([index_value_set])
- return ValueSet.from_sets(name.infer().execute(args) for name in names)
- def py__iter__(self, contextualized_node=None):
- iter_slot_names = self.get_function_slot_names('__iter__')
- if not iter_slot_names:
- return super().py__iter__(contextualized_node)
- def iterate():
- for generator in self.execute_function_slots(iter_slot_names):
- yield from generator.py__next__(contextualized_node)
- return iterate()
- def __repr__(self):
- return "<%s of %s>" % (self.__class__.__name__, self.class_value)
- class CompiledInstance(AbstractInstanceValue):
- # This is not really a compiled class, it's just an instance from a
- # compiled class.
- def __init__(self, inference_state, parent_context, class_value, arguments):
- super().__init__(inference_state, parent_context, class_value)
- self._arguments = arguments
- def get_filters(self, origin_scope=None, include_self_names=True):
- class_value = self.get_annotated_class_object()
- class_filters = class_value.get_filters(
- origin_scope=origin_scope,
- is_instance=True,
- )
- for f in class_filters:
- yield CompiledInstanceClassFilter(self, f)
- @property
- def name(self):
- return compiled.CompiledValueName(self, self.class_value.name.string_name)
- def is_stub(self):
- return False
- class _BaseTreeInstance(AbstractInstanceValue):
- @property
- def array_type(self):
- name = self.class_value.py__name__()
- if name in ['list', 'set', 'dict'] \
- and self.parent_context.get_root_context().is_builtins_module():
- return name
- return None
- @property
- def name(self):
- return ValueName(self, self.class_value.name.tree_name)
- def get_filters(self, origin_scope=None, include_self_names=True):
- class_value = self.get_annotated_class_object()
- if include_self_names:
- for cls in class_value.py__mro__():
- if not cls.is_compiled():
- # In this case we're excluding compiled objects that are
- # not fake objects. It doesn't make sense for normal
- # compiled objects to search for self variables.
- yield SelfAttributeFilter(self, class_value, cls.as_context(), origin_scope)
- class_filters = class_value.get_filters(
- origin_scope=origin_scope,
- is_instance=True,
- )
- for f in class_filters:
- if isinstance(f, ClassFilter):
- yield InstanceClassFilter(self, f)
- elif isinstance(f, CompiledValueFilter):
- yield CompiledInstanceClassFilter(self, f)
- else:
- # Propably from the metaclass.
- yield f
- @inference_state_method_cache()
- def create_instance_context(self, class_context, node):
- new = node
- while True:
- func_node = new
- new = search_ancestor(new, 'funcdef', 'classdef')
- if class_context.tree_node is new:
- func = FunctionValue.from_context(class_context, func_node)
- bound_method = BoundMethod(self, class_context, func)
- if func_node.name.value == '__init__':
- context = bound_method.as_context(self._arguments)
- else:
- context = bound_method.as_context()
- break
- return context.create_context(node)
- def py__getattribute__alternatives(self, string_name):
- '''
- Since nothing was inferred, now check the __getattr__ and
- __getattribute__ methods. Stubs don't need to be checked, because
- they don't contain any logic.
- '''
- if self.is_stub():
- return NO_VALUES
- name = compiled.create_simple_object(self.inference_state, string_name)
- # This is a little bit special. `__getattribute__` is in Python
- # executed before `__getattr__`. But: I know no use case, where
- # this could be practical and where Jedi would return wrong types.
- # If you ever find something, let me know!
- # We are inversing this, because a hand-crafted `__getattribute__`
- # could still call another hand-crafted `__getattr__`, but not the
- # other way around.
- if is_big_annoying_library(self.parent_context):
- return NO_VALUES
- names = (self.get_function_slot_names('__getattr__')
- or self.get_function_slot_names('__getattribute__'))
- return self.execute_function_slots(names, name)
- def py__next__(self, contextualized_node=None):
- name = u'__next__'
- next_slot_names = self.get_function_slot_names(name)
- if next_slot_names:
- yield LazyKnownValues(
- self.execute_function_slots(next_slot_names)
- )
- else:
- debug.warning('Instance has no __next__ function in %s.', self)
- def py__call__(self, arguments):
- names = self.get_function_slot_names('__call__')
- if not names:
- # Means the Instance is not callable.
- return super().py__call__(arguments)
- return ValueSet.from_sets(name.infer().execute(arguments) for name in names)
- def py__get__(self, instance, class_value):
- """
- obj may be None.
- """
- # Arguments in __get__ descriptors are obj, class.
- # `method` is the new parent of the array, don't know if that's good.
- for cls in self.class_value.py__mro__():
- result = cls.py__get__on_class(self, instance, class_value)
- if result is not NotImplemented:
- return result
- names = self.get_function_slot_names('__get__')
- if names:
- if instance is None:
- instance = compiled.builtin_from_name(self.inference_state, 'None')
- return self.execute_function_slots(names, instance, class_value)
- else:
- return ValueSet([self])
- class TreeInstance(_BaseTreeInstance):
- def __init__(self, inference_state, parent_context, class_value, arguments):
- # I don't think that dynamic append lookups should happen here. That
- # sounds more like something that should go to py__iter__.
- if class_value.py__name__() in ['list', 'set'] \
- and parent_context.get_root_context().is_builtins_module():
- # compare the module path with the builtin name.
- if settings.dynamic_array_additions:
- arguments = get_dynamic_array_instance(self, arguments)
- super().__init__(inference_state, parent_context, class_value)
- self._arguments = arguments
- self.tree_node = class_value.tree_node
- # This can recurse, if the initialization of the class includes a reference
- # to itself.
- @inference_state_method_cache(default=None)
- def _get_annotated_class_object(self):
- from jedi.inference.gradual.annotation import py__annotations__, \
- infer_type_vars_for_execution
- args = InstanceArguments(self, self._arguments)
- for signature in self.class_value.py__getattribute__('__init__').get_signatures():
- # Just take the first result, it should always be one, because we
- # control the typeshed code.
- funcdef = signature.value.tree_node
- if funcdef is None or funcdef.type != 'funcdef' \
- or not signature.matches_signature(args):
- # First check if the signature even matches, if not we don't
- # need to infer anything.
- continue
- bound_method = BoundMethod(self, self.class_value.as_context(), signature.value)
- all_annotations = py__annotations__(funcdef)
- type_var_dict = infer_type_vars_for_execution(bound_method, args, all_annotations)
- if type_var_dict:
- defined, = self.class_value.define_generics(
- infer_type_vars_for_execution(signature.value, args, all_annotations),
- )
- debug.dbg('Inferred instance value as %s', defined, color='BLUE')
- return defined
- return None
- def get_annotated_class_object(self):
- return self._get_annotated_class_object() or self.class_value
- def get_key_values(self):
- values = NO_VALUES
- if self.array_type == 'dict':
- for i, (key, instance) in enumerate(self._arguments.unpack()):
- if key is None and i == 0:
- values |= ValueSet.from_sets(
- v.get_key_values()
- for v in instance.infer()
- if v.array_type == 'dict'
- )
- if key:
- values |= ValueSet([compiled.create_simple_object(
- self.inference_state,
- key,
- )])
- return values
- def py__simple_getitem__(self, index):
- if self.array_type == 'dict':
- # Logic for dict({'foo': bar}) and dict(foo=bar)
- # reversed, because:
- # >>> dict({'a': 1}, a=3)
- # {'a': 3}
- # TODO tuple initializations
- # >>> dict([('a', 4)])
- # {'a': 4}
- for key, lazy_context in reversed(list(self._arguments.unpack())):
- if key is None:
- values = ValueSet.from_sets(
- dct_value.py__simple_getitem__(index)
- for dct_value in lazy_context.infer()
- if dct_value.array_type == 'dict'
- )
- if values:
- return values
- else:
- if key == index:
- return lazy_context.infer()
- return super().py__simple_getitem__(index)
- def __repr__(self):
- return "<%s of %s(%s)>" % (self.__class__.__name__, self.class_value,
- self._arguments)
- class AnonymousInstance(_BaseTreeInstance):
- _arguments = None
- class CompiledInstanceName(NameWrapper):
- @iterator_to_value_set
- def infer(self):
- for result_value in self._wrapped_name.infer():
- if result_value.api_type == 'function':
- yield CompiledBoundMethod(result_value)
- else:
- yield result_value
- class CompiledInstanceClassFilter(AbstractFilter):
- def __init__(self, instance, f):
- self._instance = instance
- self._class_filter = f
- def get(self, name):
- return self._convert(self._class_filter.get(name))
- def values(self):
- return self._convert(self._class_filter.values())
- def _convert(self, names):
- return [CompiledInstanceName(n) for n in names]
- class BoundMethod(FunctionMixin, ValueWrapper):
- def __init__(self, instance, class_context, function):
- super().__init__(function)
- self.instance = instance
- self._class_context = class_context
- def is_bound_method(self):
- return True
- @property
- def name(self):
- return FunctionNameInClass(
- self._class_context,
- super().name
- )
- def py__class__(self):
- c, = values_from_qualified_names(self.inference_state, 'types', 'MethodType')
- return c
- def _get_arguments(self, arguments):
- assert arguments is not None
- return InstanceArguments(self.instance, arguments)
- def _as_context(self, arguments=None):
- if arguments is None:
- return AnonymousMethodExecutionContext(self.instance, self)
- arguments = self._get_arguments(arguments)
- return MethodExecutionContext(self.instance, self, arguments)
- def py__call__(self, arguments):
- if isinstance(self._wrapped_value, OverloadedFunctionValue):
- return self._wrapped_value.py__call__(self._get_arguments(arguments))
- function_execution = self.as_context(arguments)
- return function_execution.infer()
- def get_signature_functions(self):
- return [
- BoundMethod(self.instance, self._class_context, f)
- for f in self._wrapped_value.get_signature_functions()
- ]
- def get_signatures(self):
- return [sig.bind(self) for sig in super().get_signatures()]
- def __repr__(self):
- return '<%s: %s>' % (self.__class__.__name__, self._wrapped_value)
- class CompiledBoundMethod(ValueWrapper):
- def is_bound_method(self):
- return True
- def get_signatures(self):
- return [sig.bind(self) for sig in self._wrapped_value.get_signatures()]
- class SelfName(TreeNameDefinition):
- """
- This name calculates the parent_context lazily.
- """
- def __init__(self, instance, class_context, tree_name):
- self._instance = instance
- self.class_context = class_context
- self.tree_name = tree_name
- @property
- def parent_context(self):
- return self._instance.create_instance_context(self.class_context, self.tree_name)
- def get_defining_qualified_value(self):
- return self._instance
- def infer(self):
- stmt = search_ancestor(self.tree_name, 'expr_stmt')
- if stmt is not None:
- if stmt.children[1].type == "annassign":
- from jedi.inference.gradual.annotation import infer_annotation
- values = infer_annotation(
- self.parent_context, stmt.children[1].children[1]
- ).execute_annotation()
- if values:
- return values
- return super().infer()
- class LazyInstanceClassName(NameWrapper):
- def __init__(self, instance, class_member_name):
- super().__init__(class_member_name)
- self._instance = instance
- @iterator_to_value_set
- def infer(self):
- for result_value in self._wrapped_name.infer():
- yield from result_value.py__get__(self._instance, self._instance.py__class__())
- def get_signatures(self):
- return self.infer().get_signatures()
- def get_defining_qualified_value(self):
- return self._instance
- class InstanceClassFilter(AbstractFilter):
- """
- This filter is special in that it uses the class filter and wraps the
- resulting names in LazyInstanceClassName. The idea is that the class name
- filtering can be very flexible and always be reflected in instances.
- """
- def __init__(self, instance, class_filter):
- self._instance = instance
- self._class_filter = class_filter
- def get(self, name):
- return self._convert(self._class_filter.get(name))
- def values(self):
- return self._convert(self._class_filter.values())
- def _convert(self, names):
- return [
- LazyInstanceClassName(self._instance, n)
- for n in names
- ]
- def __repr__(self):
- return '<%s for %s>' % (self.__class__.__name__, self._class_filter)
- class SelfAttributeFilter(ClassFilter):
- """
- This class basically filters all the use cases where `self.*` was assigned.
- """
- def __init__(self, instance, instance_class, node_context, origin_scope):
- super().__init__(
- class_value=instance_class,
- node_context=node_context,
- origin_scope=origin_scope,
- is_instance=True,
- )
- self._instance = instance
- def _filter(self, names):
- start, end = self._parser_scope.start_pos, self._parser_scope.end_pos
- names = [n for n in names if start < n.start_pos < end]
- return self._filter_self_names(names)
- def _filter_self_names(self, names):
- for name in names:
- trailer = name.parent
- if trailer.type == 'trailer' \
- and len(trailer.parent.children) == 2 \
- and trailer.children[0] == '.':
- if name.is_definition() and self._access_possible(name):
- # TODO filter non-self assignments instead of this bad
- # filter.
- if self._is_in_right_scope(trailer.parent.children[0], name):
- yield name
- def _is_in_right_scope(self, self_name, name):
- self_context = self._node_context.create_context(self_name)
- names = self_context.goto(self_name, position=self_name.start_pos)
- return any(
- n.api_type == 'param'
- and n.tree_name.get_definition().position_index == 0
- and n.parent_context.tree_node is self._parser_scope
- for n in names
- )
- def _convert_names(self, names):
- return [SelfName(self._instance, self._node_context, name) for name in names]
- def _check_flows(self, names):
- return names
- class InstanceArguments(TreeArgumentsWrapper):
- def __init__(self, instance, arguments):
- super().__init__(arguments)
- self.instance = instance
- def unpack(self, func=None):
- yield None, LazyKnownValue(self.instance)
- yield from self._wrapped_arguments.unpack(func)
|