1
0
forked from VimPlug/jedi
Files
jedi-fork/jedi/inference/context.py
2019-08-22 23:13:42 +02:00

256 lines
8.1 KiB
Python

from abc import abstractmethod
from jedi.inference.filters import ParserTreeFilter, MergedFilter, \
GlobalNameFilter
from jedi import parser_utils
class AbstractContext(object):
"""
Should be defined, otherwise the API returns empty types.
"""
predefined_names = {}
def __init__(self, value):
self.inference_state = value.inference_state
self._value = value
@abstractmethod
def get_filters(self, until_position=None, origin_scope=None):
raise NotImplementedError
def get_root_context(self):
return self._value.get_root_context()
def create_context(self, node, node_is_value=False):
from jedi.inference.value import ClassValue, FunctionValue, \
AnonymousInstance, BoundMethod
def from_scope_node(scope_node, is_nested=True):
if scope_node == base_node:
return self
is_funcdef = scope_node.type in ('funcdef', 'lambdef')
parent_scope = parser_utils.get_parent_scope(scope_node)
parent_context = from_scope_node(parent_scope)
if is_funcdef:
func = FunctionValue.from_context(parent_context, scope_node)
if parent_context.is_class():
# TODO _value private access!
instance = AnonymousInstance(
self.inference_state, parent_context.parent_context, parent_context._value)
func = BoundMethod(
instance=instance,
function=func
)
return func.as_context()
elif scope_node.type == 'classdef':
return ClassValue(self.inference_state, parent_context, scope_node).as_context()
elif scope_node.type in ('comp_for', 'sync_comp_for'):
if node.start_pos >= scope_node.children[-1].start_pos:
return parent_context
return CompForContext(parent_context, scope_node)
raise Exception("There's a scope that was not managed.")
base_node = self.tree_node
if node_is_value and parser_utils.is_scope(node):
scope_node = node
else:
def parent_scope(node):
while True:
node = node.parent
if parser_utils.is_scope(node):
return node
elif node.type in ('argument', 'testlist_comp'):
if node.children[1].type in ('comp_for', 'sync_comp_for'):
return node.children[1]
elif node.type == 'dictorsetmaker':
for n in node.children[1:4]:
# In dictionaries it can be pretty much anything.
if n.type in ('comp_for', 'sync_comp_for'):
return n
scope_node = parent_scope(node)
if scope_node.type in ('funcdef', 'classdef'):
colon = scope_node.children[scope_node.children.index(':')]
if node.start_pos < colon.start_pos:
parent = node.parent
if not (parent.type == 'param' and parent.name == node):
scope_node = parent_scope(scope_node)
return from_scope_node(scope_node, is_nested=True)
def goto(self, name_or_str, position):
from jedi.inference import finder
f = finder.NameFinder(self.inference_state, self, self, name_or_str, position)
filters = f.get_global_filters()
return f.filter_name(filters)
def py__getattribute__(self, name_or_str, name_value=None, position=None,
analysis_errors=True):
"""
:param position: Position of the last statement -> tuple of line, column
"""
if name_value is None:
name_value = self
from jedi.inference import finder
f = finder.NameFinder(self.inference_state, self, name_value, name_or_str,
position, analysis_errors=analysis_errors)
filters = f.get_global_filters()
return f.find(filters, attribute_lookup=False)
@property
def tree_node(self):
return self._value.tree_node
@property
def parent_context(self):
return self._value.parent_context
def is_module(self):
return self._value.is_module()
def is_builtins_module(self):
return self._value == self.inference_state.builtins_module
def is_class(self):
return self._value.is_class()
def is_stub(self):
return self._value.is_stub()
def is_instance(self):
return self._value.is_instance()
def is_compiled(self):
return self._value.is_compiled()
def py__name__(self):
return self._value.py__name__()
def get_qualified_names(self):
return self._value.get_qualified_names()
def py__doc__(self):
return self._value.py__doc__()
def infer_node(self, node):
return self.inference_state.infer_element(self, node)
def __repr__(self):
return '%s(%s)' % (self.__class__.__name__, self._value)
class FunctionContext(AbstractContext):
def get_filters(self, until_position=None, origin_scope=None):
yield ParserTreeFilter(
self.inference_state,
parent_context=self,
until_position=until_position,
origin_scope=origin_scope
)
class ModuleContext(AbstractContext):
def py__file__(self):
return self._value.py__file__()
@property
def py__package__(self):
return self._value.py__package__
@property
def is_package(self):
return self._value.is_package
def get_filters(self, until_position=None, origin_scope=None):
filters = self._value.get_filters(origin_scope)
# Skip the first filter and replace it.
next(filters)
yield MergedFilter(
ParserTreeFilter(
parent_context=self,
until_position=until_position,
origin_scope=origin_scope
),
GlobalNameFilter(self, self.tree_node),
)
for f in filters: # Python 2...
yield f
@property
def string_names(self):
return self._value.string_names
@property
def code_lines(self):
return self._value.code_lines
def get_value(self):
"""
This is the only function that converts a context back to a value.
This is necessary for stub -> python conversion and vice versa. However
this method shouldn't be move to AbstractContext.
"""
return self._value
class NamespaceContext(AbstractContext):
def get_filters(self, until_position=None, origin_scope=None):
return self._value.get_filters()
def py__file__(self):
return self._value.py__file__()
class ClassContext(AbstractContext):
def get_filters(self, until_position=None, origin_scope=None):
yield self.get_global_filter(until_position, origin_scope)
def get_global_filter(self, until_position=None, origin_scope=None):
return ParserTreeFilter(
parent_context=self,
until_position=until_position,
origin_scope=origin_scope
)
class CompForContext(AbstractContext):
def __init__(self, parent_context, comp_for):
self._parent_context = parent_context
self.inference_state = parent_context.inference_state
self._tree_node = comp_for
@property
def parent_context(self):
return self._parent_context
def get_root_context(self):
return self._parent_context.get_root_context()
def is_instance(self):
return False
def is_compiled(self):
return False
@property
def tree_node(self):
return self._tree_node
def get_filters(self, until_position=None, origin_scope=None):
yield ParserTreeFilter(self)
class CompiledContext(AbstractContext):
def get_filters(self, until_position=None, origin_scope=None):
return self._value.get_filters()
def get_value(self):
return self._value
def py__file__(self):
return self._value.py__file__()