You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ORPA-pyOpenRPA/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/jedi/evaluate/context/instance.py

484 lines
18 KiB

6 years ago
from abc import abstractproperty
from jedi import debug
from jedi import settings
from jedi.evaluate import compiled
from jedi.evaluate import filters
from jedi.evaluate.base_context import Context, NO_CONTEXTS, ContextSet, \
iterator_to_context_set
from jedi.evaluate.lazy_context import LazyKnownContext, LazyKnownContexts
from jedi.evaluate.cache import evaluator_method_cache
from jedi.evaluate.arguments import AbstractArguments, AnonymousArguments
from jedi.evaluate.context.function import FunctionExecutionContext, \
FunctionContext, AbstractFunction
from jedi.evaluate.context.klass import ClassContext, apply_py__get__, ClassFilter
from jedi.evaluate.context import iterable
from jedi.parser_utils import get_parent_scope
class InstanceExecutedParam(object):
def __init__(self, instance):
self._instance = instance
def infer(self):
return ContextSet(self._instance)
class AnonymousInstanceArguments(AnonymousArguments):
def __init__(self, instance):
self._instance = instance
def get_executed_params(self, execution_context):
from jedi.evaluate.dynamic import search_params
self_param = InstanceExecutedParam(self._instance)
tree_params = execution_context.tree_node.get_params()
if len(tree_params) == 1:
# If the only param is self, we don't need to try to find
# executions of this function, we have all the params already.
return [self_param]
executed_params = list(search_params(
execution_context.evaluator,
execution_context,
execution_context.tree_node
))
executed_params[0] = self_param
return executed_params
class AbstractInstanceContext(Context):
"""
This class is used to evaluate instances.
"""
api_type = u'instance'
def __init__(self, evaluator, parent_context, class_context, var_args):
super(AbstractInstanceContext, self).__init__(evaluator, parent_context)
# Generated instances are classes that are just generated by self
# (No var_args) used.
self.class_context = class_context
self.var_args = var_args
def is_class(self):
return False
@property
def py__call__(self):
names = self.get_function_slot_names(u'__call__')
if not names:
# Means the Instance is not callable.
raise AttributeError
def execute(arguments):
return ContextSet.from_sets(name.infer().execute(arguments) for name in names)
return execute
def py__class__(self):
return self.class_context
def py__bool__(self):
# Signalize that we don't know about the bool type.
return None
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, *evaluated_args):
return ContextSet.from_sets(
name.infer().execute_evaluated(*evaluated_args)
for name in names
)
def py__get__(self, obj):
# Arguments in __get__ descriptors are obj, class.
# `method` is the new parent of the array, don't know if that's good.
names = self.get_function_slot_names(u'__get__')
if names:
if isinstance(obj, AbstractInstanceContext):
return self.execute_function_slots(names, obj, obj.class_context)
else:
none_obj = compiled.builtin_from_name(self.evaluator, u'None')
return self.execute_function_slots(names, none_obj, obj)
else:
return ContextSet(self)
def get_filters(self, search_global=None, until_position=None,
origin_scope=None, include_self_names=True):
if include_self_names:
for cls in self.class_context.py__mro__():
if not isinstance(cls, compiled.CompiledObject) \
or cls.tree_node is not None:
# 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.evaluator, self, cls, origin_scope)
for cls in self.class_context.py__mro__():
if isinstance(cls, compiled.CompiledObject):
yield CompiledInstanceClassFilter(self.evaluator, self, cls)
else:
yield InstanceClassFilter(self.evaluator, self, cls, origin_scope)
def py__getitem__(self, index):
try:
names = self.get_function_slot_names(u'__getitem__')
except KeyError:
debug.warning('No __getitem__, cannot access the array.')
return NO_CONTEXTS
else:
index_obj = compiled.create_simple_object(self.evaluator, index)
return self.execute_function_slots(names, index_obj)
def py__iter__(self):
iter_slot_names = self.get_function_slot_names(u'__iter__')
if not iter_slot_names:
debug.warning('No __iter__ on %s.' % self)
return
for generator in self.execute_function_slots(iter_slot_names):
if isinstance(generator, AbstractInstanceContext):
# `__next__` logic.
if self.evaluator.environment.version_info.major == 2:
name = u'next'
else:
name = u'__next__'
iter_slot_names = generator.get_function_slot_names(name)
if iter_slot_names:
yield LazyKnownContexts(
generator.execute_function_slots(iter_slot_names)
)
else:
debug.warning('Instance has no __next__ function in %s.', generator)
else:
for lazy_context in generator.py__iter__():
yield lazy_context
@abstractproperty
def name(self):
pass
def _create_init_execution(self, class_context, bound_method):
return bound_method.get_function_execution(self.var_args)
def create_init_executions(self):
for name in self.get_function_slot_names(u'__init__'):
if isinstance(name, LazyInstanceClassName):
function = FunctionContext.from_context(
self.parent_context,
name.tree_name.parent
)
bound_method = BoundMethod(self, name.class_context, function)
yield self._create_init_execution(name.class_context, bound_method)
@evaluator_method_cache()
def create_instance_context(self, class_context, node):
if node.parent.type in ('funcdef', 'classdef'):
node = node.parent
scope = get_parent_scope(node)
if scope == class_context.tree_node:
return class_context
else:
parent_context = self.create_instance_context(class_context, scope)
if scope.type == 'funcdef':
func = FunctionContext.from_context(
parent_context,
scope,
)
bound_method = BoundMethod(self, class_context, func)
if scope.name.value == '__init__' and parent_context == class_context:
return self._create_init_execution(class_context, bound_method)
else:
return bound_method.get_function_execution()
elif scope.type == 'classdef':
class_context = ClassContext(self.evaluator, parent_context, scope)
return class_context
elif scope.type == 'comp_for':
# Comprehensions currently don't have a special scope in Jedi.
return self.create_instance_context(class_context, scope)
else:
raise NotImplementedError
return class_context
def __repr__(self):
return "<%s of %s(%s)>" % (self.__class__.__name__, self.class_context,
self.var_args)
class CompiledInstance(AbstractInstanceContext):
def __init__(self, evaluator, parent_context, class_context, var_args):
self._original_var_args = var_args
# I don't think that dynamic append lookups should happen here. That
# sounds more like something that should go to py__iter__.
if class_context.py__name__() in ['list', 'set'] \
and parent_context.get_root_context() == evaluator.builtins_module:
# compare the module path with the builtin name.
if settings.dynamic_array_additions:
var_args = iterable.get_dynamic_array_instance(self, var_args)
super(CompiledInstance, self).__init__(evaluator, parent_context, class_context, var_args)
@property
def name(self):
return compiled.CompiledContextName(self, self.class_context.name.string_name)
def create_instance_context(self, class_context, node):
if get_parent_scope(node).type == 'classdef':
return class_context
else:
return super(CompiledInstance, self).create_instance_context(class_context, node)
def get_first_non_keyword_argument_contexts(self):
key, lazy_context = next(self._original_var_args.unpack(), ('', None))
if key is not None:
return NO_CONTEXTS
return lazy_context.infer()
class TreeInstance(AbstractInstanceContext):
def __init__(self, evaluator, parent_context, class_context, var_args):
super(TreeInstance, self).__init__(evaluator, parent_context,
class_context, var_args)
self.tree_node = class_context.tree_node
@property
def name(self):
return filters.ContextName(self, self.class_context.name.tree_name)
class AnonymousInstance(TreeInstance):
def __init__(self, evaluator, parent_context, class_context):
super(AnonymousInstance, self).__init__(
evaluator,
parent_context,
class_context,
var_args=AnonymousInstanceArguments(self),
)
class CompiledInstanceName(compiled.CompiledName):
def __init__(self, evaluator, instance, klass, name):
super(CompiledInstanceName, self).__init__(
evaluator,
klass.parent_context,
name.string_name
)
self._instance = instance
self._class = klass
self._class_member_name = name
@iterator_to_context_set
def infer(self):
for result_context in self._class_member_name.infer():
is_function = result_context.api_type == 'function'
if result_context.tree_node is not None and is_function:
yield BoundMethod(self._instance, self._class, result_context)
else:
if is_function:
yield CompiledBoundMethod(result_context)
else:
yield result_context
class CompiledInstanceClassFilter(filters.AbstractFilter):
name_class = CompiledInstanceName
def __init__(self, evaluator, instance, klass):
self._evaluator = evaluator
self._instance = instance
self._class = klass
self._class_filter = next(klass.get_filters(is_instance=True))
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(self._evaluator, self._instance, self._class, n)
for n in names
]
class BoundMethod(AbstractFunction):
def __init__(self, instance, klass, function):
super(BoundMethod, self).__init__(
function.evaluator,
function.parent_context,
function.tree_node,
)
self._instance = instance
self._class = klass
self._function = function
def py__class__(self):
return compiled.get_special_object(self.evaluator, u'BOUND_METHOD_CLASS')
def get_function_execution(self, arguments=None):
if arguments is None:
arguments = AnonymousInstanceArguments(self._instance)
arguments = InstanceArguments(self._instance, arguments)
if isinstance(self._function, compiled.CompiledObject):
# This is kind of weird, because it's coming from a compiled object
# and we're not sure if we want that in the future.
return FunctionExecutionContext(
self.evaluator, self.parent_context, self, arguments
)
return self._function.get_function_execution(arguments)
def __repr__(self):
return '<%s: %s>' % (self.__class__.__name__, self._function)
class CompiledBoundMethod(compiled.CompiledObject):
def __init__(self, func):
super(CompiledBoundMethod, self).__init__(
func.evaluator, func.access_handle, func.parent_context, func.tree_node)
def get_param_names(self):
return list(super(CompiledBoundMethod, self).get_param_names())[1:]
class SelfName(filters.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)
class LazyInstanceClassName(object):
def __init__(self, instance, class_context, class_member_name):
self._instance = instance
self.class_context = class_context
self._class_member_name = class_member_name
@iterator_to_context_set
def infer(self):
for result_context in self._class_member_name.infer():
if isinstance(result_context, FunctionContext):
# Classes are never used to resolve anything within the
# functions. Only other functions and modules will resolve
# those things.
yield BoundMethod(self._instance, self.class_context, result_context)
else:
for c in apply_py__get__(result_context, self._instance):
yield c
def __getattr__(self, name):
return getattr(self._class_member_name, name)
class InstanceClassFilter(filters.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, evaluator, context, class_context, origin_scope):
self._instance = context
self._class_context = class_context
self._class_filter = next(class_context.get_filters(
search_global=False,
origin_scope=origin_scope,
is_instance=True,
))
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, self._class_context, n) for n in names]
class SelfAttributeFilter(ClassFilter):
"""
This class basically filters all the use cases where `self.*` was assigned.
"""
name_class = SelfName
def __init__(self, evaluator, context, class_context, origin_scope):
super(SelfAttributeFilter, self).__init__(
evaluator=evaluator,
context=context,
node_context=class_context,
origin_scope=origin_scope,
is_instance=True,
)
self._class_context = class_context
def _filter(self, names):
names = self._filter_self_names(names)
if isinstance(self._parser_scope, compiled.CompiledObject) and False:
# This would be for builtin skeletons, which are not yet supported.
return list(names)
else:
start, end = self._parser_scope.start_pos, self._parser_scope.end_pos
return [n for n in names if start < n.start_pos < end]
def _filter_self_names(self, names):
for name in names:
trailer = name.parent
if trailer.type == 'trailer' \
and len(trailer.children) == 2 \
and trailer.children[0] == '.':
if name.is_definition() and self._access_possible(name):
yield name
def _convert_names(self, names):
return [self.name_class(self.context, self._class_context, name) for name in names]
def _check_flows(self, names):
return names
class InstanceArguments(AbstractArguments):
def __init__(self, instance, var_args):
self.instance = instance
self._var_args = var_args
@property
def argument_node(self):
return self._var_args.argument_node
@property
def trailer(self):
return self._var_args.trailer
def unpack(self, func=None):
yield None, LazyKnownContext(self.instance)
for values in self._var_args.unpack(func):
yield values
def get_calling_nodes(self):
return self._var_args.get_calling_nodes()
def get_executed_params(self, execution_context):
if isinstance(self._var_args, AnonymousInstanceArguments):
return self._var_args.get_executed_params(execution_context)
return super(InstanceArguments, self).get_executed_params(execution_context)