You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			678 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			678 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			Python
		
	
from abc import abstractmethod
 | 
						|
from inspect import Parameter
 | 
						|
from typing import Optional, Tuple
 | 
						|
 | 
						|
from parso.tree import search_ancestor
 | 
						|
 | 
						|
from jedi.parser_utils import find_statement_documentation, clean_scope_docstring
 | 
						|
from jedi.inference.utils import unite
 | 
						|
from jedi.inference.base_value import ValueSet, NO_VALUES
 | 
						|
from jedi.inference.cache import inference_state_method_cache
 | 
						|
from jedi.inference import docstrings
 | 
						|
from jedi.cache import memoize_method
 | 
						|
from jedi.inference.helpers import deep_ast_copy, infer_call_of_leaf
 | 
						|
from jedi.plugins import plugin_manager
 | 
						|
 | 
						|
 | 
						|
def _merge_name_docs(names):
 | 
						|
    doc = ''
 | 
						|
    for name in names:
 | 
						|
        if doc:
 | 
						|
            # In case we have multiple values, just return all of them
 | 
						|
            # separated by a few dashes.
 | 
						|
            doc += '\n' + '-' * 30 + '\n'
 | 
						|
        doc += name.py__doc__()
 | 
						|
    return doc
 | 
						|
 | 
						|
 | 
						|
class AbstractNameDefinition:
 | 
						|
    start_pos: Optional[Tuple[int, int]] = None
 | 
						|
    string_name: str
 | 
						|
    parent_context = None
 | 
						|
    tree_name = None
 | 
						|
    is_value_name = True
 | 
						|
    """
 | 
						|
    Used for the Jedi API to know if it's a keyword or an actual name.
 | 
						|
    """
 | 
						|
 | 
						|
    @abstractmethod
 | 
						|
    def infer(self):
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
    @abstractmethod
 | 
						|
    def goto(self):
 | 
						|
        # Typically names are already definitions and therefore a goto on that
 | 
						|
        # name will always result on itself.
 | 
						|
        return {self}
 | 
						|
 | 
						|
    def get_qualified_names(self, include_module_names=False):
 | 
						|
        qualified_names = self._get_qualified_names()
 | 
						|
        if qualified_names is None or not include_module_names:
 | 
						|
            return qualified_names
 | 
						|
 | 
						|
        module_names = self.get_root_context().string_names
 | 
						|
        if module_names is None:
 | 
						|
            return None
 | 
						|
        return module_names + qualified_names
 | 
						|
 | 
						|
    def _get_qualified_names(self):
 | 
						|
        # By default, a name has no qualified names.
 | 
						|
        return None
 | 
						|
 | 
						|
    def get_root_context(self):
 | 
						|
        return self.parent_context.get_root_context()
 | 
						|
 | 
						|
    def get_public_name(self):
 | 
						|
        return self.string_name
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        if self.start_pos is None:
 | 
						|
            return '<%s: string_name=%s>' % (self.__class__.__name__, self.string_name)
 | 
						|
        return '<%s: string_name=%s start_pos=%s>' % (self.__class__.__name__,
 | 
						|
                                                      self.string_name, self.start_pos)
 | 
						|
 | 
						|
    def is_import(self):
 | 
						|
        return False
 | 
						|
 | 
						|
    def py__doc__(self):
 | 
						|
        return ''
 | 
						|
 | 
						|
    @property
 | 
						|
    def api_type(self):
 | 
						|
        return self.parent_context.api_type
 | 
						|
 | 
						|
    def get_defining_qualified_value(self):
 | 
						|
        """
 | 
						|
        Returns either None or the value that is public and qualified. Won't
 | 
						|
        return a function, because a name in a function is never public.
 | 
						|
        """
 | 
						|
        return None
 | 
						|
 | 
						|
 | 
						|
class AbstractArbitraryName(AbstractNameDefinition):
 | 
						|
    """
 | 
						|
    When you e.g. want to complete dicts keys, you probably want to complete
 | 
						|
    string literals, which is not really a name, but for Jedi we use this
 | 
						|
    concept of Name for completions as well.
 | 
						|
    """
 | 
						|
    is_value_name = False
 | 
						|
 | 
						|
    def __init__(self, inference_state, string):
 | 
						|
        self.inference_state = inference_state
 | 
						|
        self.string_name = string
 | 
						|
        self.parent_context = inference_state.builtins_module
 | 
						|
 | 
						|
    def infer(self):
 | 
						|
        return NO_VALUES
 | 
						|
 | 
						|
 | 
						|
class AbstractTreeName(AbstractNameDefinition):
 | 
						|
    def __init__(self, parent_context, tree_name):
 | 
						|
        self.parent_context = parent_context
 | 
						|
        self.tree_name = tree_name
 | 
						|
 | 
						|
    def get_qualified_names(self, include_module_names=False):
 | 
						|
        import_node = search_ancestor(self.tree_name, 'import_name', 'import_from')
 | 
						|
        # For import nodes we cannot just have names, because it's very unclear
 | 
						|
        # how they would look like. For now we just ignore them in most cases.
 | 
						|
        # In case of level == 1, it works always, because it's like a submodule
 | 
						|
        # lookup.
 | 
						|
        if import_node is not None and not (import_node.level == 1
 | 
						|
                                            and self.get_root_context().get_value().is_package()):
 | 
						|
            # TODO improve the situation for when level is present.
 | 
						|
            if include_module_names and not import_node.level:
 | 
						|
                return tuple(n.value for n in import_node.get_path_for_name(self.tree_name))
 | 
						|
            else:
 | 
						|
                return None
 | 
						|
 | 
						|
        return super().get_qualified_names(include_module_names)
 | 
						|
 | 
						|
    def _get_qualified_names(self):
 | 
						|
        parent_names = self.parent_context.get_qualified_names()
 | 
						|
        if parent_names is None:
 | 
						|
            return None
 | 
						|
        return parent_names + (self.tree_name.value,)
 | 
						|
 | 
						|
    def get_defining_qualified_value(self):
 | 
						|
        if self.is_import():
 | 
						|
            raise NotImplementedError("Shouldn't really happen, please report")
 | 
						|
        elif self.parent_context:
 | 
						|
            return self.parent_context.get_value()  # Might be None
 | 
						|
        return None
 | 
						|
 | 
						|
    def goto(self):
 | 
						|
        context = self.parent_context
 | 
						|
        name = self.tree_name
 | 
						|
        definition = name.get_definition(import_name_always=True)
 | 
						|
        if definition is not None:
 | 
						|
            type_ = definition.type
 | 
						|
            if type_ == 'expr_stmt':
 | 
						|
                # Only take the parent, because if it's more complicated than just
 | 
						|
                # a name it's something you can "goto" again.
 | 
						|
                is_simple_name = name.parent.type not in ('power', 'trailer')
 | 
						|
                if is_simple_name:
 | 
						|
                    return [self]
 | 
						|
            elif type_ in ('import_from', 'import_name'):
 | 
						|
                from jedi.inference.imports import goto_import
 | 
						|
                module_names = goto_import(context, name)
 | 
						|
                return module_names
 | 
						|
            else:
 | 
						|
                return [self]
 | 
						|
        else:
 | 
						|
            from jedi.inference.imports import follow_error_node_imports_if_possible
 | 
						|
            values = follow_error_node_imports_if_possible(context, name)
 | 
						|
            if values is not None:
 | 
						|
                return [value.name for value in values]
 | 
						|
 | 
						|
        par = name.parent
 | 
						|
        node_type = par.type
 | 
						|
        if node_type == 'argument' and par.children[1] == '=' and par.children[0] == name:
 | 
						|
            # Named param goto.
 | 
						|
            trailer = par.parent
 | 
						|
            if trailer.type == 'arglist':
 | 
						|
                trailer = trailer.parent
 | 
						|
            if trailer.type != 'classdef':
 | 
						|
                if trailer.type == 'decorator':
 | 
						|
                    value_set = context.infer_node(trailer.children[1])
 | 
						|
                else:
 | 
						|
                    i = trailer.parent.children.index(trailer)
 | 
						|
                    to_infer = trailer.parent.children[:i]
 | 
						|
                    if to_infer[0] == 'await':
 | 
						|
                        to_infer.pop(0)
 | 
						|
                    value_set = context.infer_node(to_infer[0])
 | 
						|
                    from jedi.inference.syntax_tree import infer_trailer
 | 
						|
                    for trailer in to_infer[1:]:
 | 
						|
                        value_set = infer_trailer(context, value_set, trailer)
 | 
						|
                param_names = []
 | 
						|
                for value in value_set:
 | 
						|
                    for signature in value.get_signatures():
 | 
						|
                        for param_name in signature.get_param_names():
 | 
						|
                            if param_name.string_name == name.value:
 | 
						|
                                param_names.append(param_name)
 | 
						|
                return param_names
 | 
						|
        elif node_type == 'dotted_name':  # Is a decorator.
 | 
						|
            index = par.children.index(name)
 | 
						|
            if index > 0:
 | 
						|
                new_dotted = deep_ast_copy(par)
 | 
						|
                new_dotted.children[index - 1:] = []
 | 
						|
                values = context.infer_node(new_dotted)
 | 
						|
                return unite(
 | 
						|
                    value.goto(name, name_context=context)
 | 
						|
                    for value in values
 | 
						|
                )
 | 
						|
 | 
						|
        if node_type == 'trailer' and par.children[0] == '.':
 | 
						|
            values = infer_call_of_leaf(context, name, cut_own_trailer=True)
 | 
						|
            return values.goto(name, name_context=context)
 | 
						|
        else:
 | 
						|
            stmt = search_ancestor(
 | 
						|
                name, 'expr_stmt', 'lambdef'
 | 
						|
            ) or name
 | 
						|
            if stmt.type == 'lambdef':
 | 
						|
                stmt = name
 | 
						|
            return context.goto(name, position=stmt.start_pos)
 | 
						|
 | 
						|
    def is_import(self):
 | 
						|
        imp = search_ancestor(self.tree_name, 'import_from', 'import_name')
 | 
						|
        return imp is not None
 | 
						|
 | 
						|
    @property
 | 
						|
    def string_name(self):
 | 
						|
        return self.tree_name.value
 | 
						|
 | 
						|
    @property
 | 
						|
    def start_pos(self):
 | 
						|
        return self.tree_name.start_pos
 | 
						|
 | 
						|
 | 
						|
class ValueNameMixin:
 | 
						|
    def infer(self):
 | 
						|
        return ValueSet([self._value])
 | 
						|
 | 
						|
    def py__doc__(self):
 | 
						|
        doc = self._value.py__doc__()
 | 
						|
        if not doc and self._value.is_stub():
 | 
						|
            from jedi.inference.gradual.conversion import convert_names
 | 
						|
            names = convert_names([self], prefer_stub_to_compiled=False)
 | 
						|
            if self not in names:
 | 
						|
                return _merge_name_docs(names)
 | 
						|
        return doc
 | 
						|
 | 
						|
    def _get_qualified_names(self):
 | 
						|
        return self._value.get_qualified_names()
 | 
						|
 | 
						|
    def get_root_context(self):
 | 
						|
        if self.parent_context is None:  # A module
 | 
						|
            return self._value.as_context()
 | 
						|
        return super().get_root_context()
 | 
						|
 | 
						|
    def get_defining_qualified_value(self):
 | 
						|
        context = self.parent_context
 | 
						|
        if context is not None and (context.is_module() or context.is_class()):
 | 
						|
            return self.parent_context.get_value()  # Might be None
 | 
						|
        return None
 | 
						|
 | 
						|
    @property
 | 
						|
    def api_type(self):
 | 
						|
        return self._value.api_type
 | 
						|
 | 
						|
 | 
						|
class ValueName(ValueNameMixin, AbstractTreeName):
 | 
						|
    def __init__(self, value, tree_name):
 | 
						|
        super().__init__(value.parent_context, tree_name)
 | 
						|
        self._value = value
 | 
						|
 | 
						|
    def goto(self):
 | 
						|
        return ValueSet([self._value.name])
 | 
						|
 | 
						|
 | 
						|
class TreeNameDefinition(AbstractTreeName):
 | 
						|
    _API_TYPES = dict(
 | 
						|
        import_name='module',
 | 
						|
        import_from='module',
 | 
						|
        funcdef='function',
 | 
						|
        param='param',
 | 
						|
        classdef='class',
 | 
						|
    )
 | 
						|
 | 
						|
    def infer(self):
 | 
						|
        # Refactor this, should probably be here.
 | 
						|
        from jedi.inference.syntax_tree import tree_name_to_values
 | 
						|
        return tree_name_to_values(
 | 
						|
            self.parent_context.inference_state,
 | 
						|
            self.parent_context,
 | 
						|
            self.tree_name
 | 
						|
        )
 | 
						|
 | 
						|
    @property
 | 
						|
    def api_type(self):
 | 
						|
        definition = self.tree_name.get_definition(import_name_always=True)
 | 
						|
        if definition is None:
 | 
						|
            return 'statement'
 | 
						|
        return self._API_TYPES.get(definition.type, 'statement')
 | 
						|
 | 
						|
    def assignment_indexes(self):
 | 
						|
        """
 | 
						|
        Returns an array of tuple(int, node) of the indexes that are used in
 | 
						|
        tuple assignments.
 | 
						|
 | 
						|
        For example if the name is ``y`` in the following code::
 | 
						|
 | 
						|
            x, (y, z) = 2, ''
 | 
						|
 | 
						|
        would result in ``[(1, xyz_node), (0, yz_node)]``.
 | 
						|
 | 
						|
        When searching for b in the case ``a, *b, c = [...]`` it will return::
 | 
						|
 | 
						|
            [(slice(1, -1), abc_node)]
 | 
						|
        """
 | 
						|
        indexes = []
 | 
						|
        is_star_expr = False
 | 
						|
        node = self.tree_name.parent
 | 
						|
        compare = self.tree_name
 | 
						|
        while node is not None:
 | 
						|
            if node.type in ('testlist', 'testlist_comp', 'testlist_star_expr', 'exprlist'):
 | 
						|
                for i, child in enumerate(node.children):
 | 
						|
                    if child == compare:
 | 
						|
                        index = int(i / 2)
 | 
						|
                        if is_star_expr:
 | 
						|
                            from_end = int((len(node.children) - i) / 2)
 | 
						|
                            index = slice(index, -from_end)
 | 
						|
                        indexes.insert(0, (index, node))
 | 
						|
                        break
 | 
						|
                else:
 | 
						|
                    raise LookupError("Couldn't find the assignment.")
 | 
						|
                is_star_expr = False
 | 
						|
            elif node.type == 'star_expr':
 | 
						|
                is_star_expr = True
 | 
						|
            elif node.type in ('expr_stmt', 'sync_comp_for'):
 | 
						|
                break
 | 
						|
 | 
						|
            compare = node
 | 
						|
            node = node.parent
 | 
						|
        return indexes
 | 
						|
 | 
						|
    @property
 | 
						|
    def inference_state(self):
 | 
						|
        # Used by the cache function below
 | 
						|
        return self.parent_context.inference_state
 | 
						|
 | 
						|
    @inference_state_method_cache(default='')
 | 
						|
    def py__doc__(self):
 | 
						|
        api_type = self.api_type
 | 
						|
        if api_type in ('function', 'class', 'property'):
 | 
						|
            if self.parent_context.get_root_context().is_stub():
 | 
						|
                from jedi.inference.gradual.conversion import convert_names
 | 
						|
                names = convert_names([self], prefer_stub_to_compiled=False)
 | 
						|
                if self not in names:
 | 
						|
                    return _merge_name_docs(names)
 | 
						|
 | 
						|
            # Make sure the names are not TreeNameDefinitions anymore.
 | 
						|
            return clean_scope_docstring(self.tree_name.get_definition())
 | 
						|
 | 
						|
        if api_type == 'module':
 | 
						|
            names = self.goto()
 | 
						|
            if self not in names:
 | 
						|
                return _merge_name_docs(names)
 | 
						|
 | 
						|
        if api_type == 'statement' and self.tree_name.is_definition():
 | 
						|
            return find_statement_documentation(self.tree_name.get_definition())
 | 
						|
        return ''
 | 
						|
 | 
						|
 | 
						|
class _ParamMixin:
 | 
						|
    def maybe_positional_argument(self, include_star=True):
 | 
						|
        options = [Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD]
 | 
						|
        if include_star:
 | 
						|
            options.append(Parameter.VAR_POSITIONAL)
 | 
						|
        return self.get_kind() in options
 | 
						|
 | 
						|
    def maybe_keyword_argument(self, include_stars=True):
 | 
						|
        options = [Parameter.KEYWORD_ONLY, Parameter.POSITIONAL_OR_KEYWORD]
 | 
						|
        if include_stars:
 | 
						|
            options.append(Parameter.VAR_KEYWORD)
 | 
						|
        return self.get_kind() in options
 | 
						|
 | 
						|
    def _kind_string(self):
 | 
						|
        kind = self.get_kind()
 | 
						|
        if kind == Parameter.VAR_POSITIONAL:  # *args
 | 
						|
            return '*'
 | 
						|
        if kind == Parameter.VAR_KEYWORD:  # **kwargs
 | 
						|
            return '**'
 | 
						|
        return ''
 | 
						|
 | 
						|
    def get_qualified_names(self, include_module_names=False):
 | 
						|
        return None
 | 
						|
 | 
						|
 | 
						|
class ParamNameInterface(_ParamMixin):
 | 
						|
    api_type = 'param'
 | 
						|
 | 
						|
    def get_kind(self):
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
    def to_string(self):
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
    def get_executed_param_name(self):
 | 
						|
        """
 | 
						|
        For dealing with type inference and working around the graph, we
 | 
						|
        sometimes want to have the param name of the execution. This feels a
 | 
						|
        bit strange and we might have to refactor at some point.
 | 
						|
 | 
						|
        For now however it exists to avoid infering params when we don't really
 | 
						|
        need them (e.g. when we can just instead use annotations.
 | 
						|
        """
 | 
						|
        return None
 | 
						|
 | 
						|
    @property
 | 
						|
    def star_count(self):
 | 
						|
        kind = self.get_kind()
 | 
						|
        if kind == Parameter.VAR_POSITIONAL:
 | 
						|
            return 1
 | 
						|
        if kind == Parameter.VAR_KEYWORD:
 | 
						|
            return 2
 | 
						|
        return 0
 | 
						|
 | 
						|
    def infer_default(self):
 | 
						|
        return NO_VALUES
 | 
						|
 | 
						|
 | 
						|
class BaseTreeParamName(ParamNameInterface, AbstractTreeName):
 | 
						|
    annotation_node = None
 | 
						|
    default_node = None
 | 
						|
 | 
						|
    def to_string(self):
 | 
						|
        output = self._kind_string() + self.get_public_name()
 | 
						|
        annotation = self.annotation_node
 | 
						|
        default = self.default_node
 | 
						|
        if annotation is not None:
 | 
						|
            output += ': ' + annotation.get_code(include_prefix=False)
 | 
						|
        if default is not None:
 | 
						|
            output += '=' + default.get_code(include_prefix=False)
 | 
						|
        return output
 | 
						|
 | 
						|
    def get_public_name(self):
 | 
						|
        name = self.string_name
 | 
						|
        if name.startswith('__'):
 | 
						|
            # Params starting with __ are an equivalent to positional only
 | 
						|
            # variables in typeshed.
 | 
						|
            name = name[2:]
 | 
						|
        return name
 | 
						|
 | 
						|
    def goto(self, **kwargs):
 | 
						|
        return [self]
 | 
						|
 | 
						|
 | 
						|
class _ActualTreeParamName(BaseTreeParamName):
 | 
						|
    def __init__(self, function_value, tree_name):
 | 
						|
        super().__init__(
 | 
						|
            function_value.get_default_param_context(), tree_name)
 | 
						|
        self.function_value = function_value
 | 
						|
 | 
						|
    def _get_param_node(self):
 | 
						|
        return search_ancestor(self.tree_name, 'param')
 | 
						|
 | 
						|
    @property
 | 
						|
    def annotation_node(self):
 | 
						|
        return self._get_param_node().annotation
 | 
						|
 | 
						|
    def infer_annotation(self, execute_annotation=True, ignore_stars=False):
 | 
						|
        from jedi.inference.gradual.annotation import infer_param
 | 
						|
        values = infer_param(
 | 
						|
            self.function_value, self._get_param_node(),
 | 
						|
            ignore_stars=ignore_stars)
 | 
						|
        if execute_annotation:
 | 
						|
            values = values.execute_annotation()
 | 
						|
        return values
 | 
						|
 | 
						|
    def infer_default(self):
 | 
						|
        node = self.default_node
 | 
						|
        if node is None:
 | 
						|
            return NO_VALUES
 | 
						|
        return self.parent_context.infer_node(node)
 | 
						|
 | 
						|
    @property
 | 
						|
    def default_node(self):
 | 
						|
        return self._get_param_node().default
 | 
						|
 | 
						|
    def get_kind(self):
 | 
						|
        tree_param = self._get_param_node()
 | 
						|
        if tree_param.star_count == 1:  # *args
 | 
						|
            return Parameter.VAR_POSITIONAL
 | 
						|
        if tree_param.star_count == 2:  # **kwargs
 | 
						|
            return Parameter.VAR_KEYWORD
 | 
						|
 | 
						|
        # Params starting with __ are an equivalent to positional only
 | 
						|
        # variables in typeshed.
 | 
						|
        if tree_param.name.value.startswith('__'):
 | 
						|
            return Parameter.POSITIONAL_ONLY
 | 
						|
 | 
						|
        parent = tree_param.parent
 | 
						|
        param_appeared = False
 | 
						|
        for p in parent.children:
 | 
						|
            if param_appeared:
 | 
						|
                if p == '/':
 | 
						|
                    return Parameter.POSITIONAL_ONLY
 | 
						|
            else:
 | 
						|
                if p == '*':
 | 
						|
                    return Parameter.KEYWORD_ONLY
 | 
						|
                if p.type == 'param':
 | 
						|
                    if p.star_count:
 | 
						|
                        return Parameter.KEYWORD_ONLY
 | 
						|
                    if p == tree_param:
 | 
						|
                        param_appeared = True
 | 
						|
        return Parameter.POSITIONAL_OR_KEYWORD
 | 
						|
 | 
						|
    def infer(self):
 | 
						|
        values = self.infer_annotation()
 | 
						|
        if values:
 | 
						|
            return values
 | 
						|
 | 
						|
        doc_params = docstrings.infer_param(self.function_value, self._get_param_node())
 | 
						|
        return doc_params
 | 
						|
 | 
						|
 | 
						|
class AnonymousParamName(_ActualTreeParamName):
 | 
						|
    @plugin_manager.decorate(name='goto_anonymous_param')
 | 
						|
    def goto(self):
 | 
						|
        return super().goto()
 | 
						|
 | 
						|
    @plugin_manager.decorate(name='infer_anonymous_param')
 | 
						|
    def infer(self):
 | 
						|
        values = super().infer()
 | 
						|
        if values:
 | 
						|
            return values
 | 
						|
        from jedi.inference.dynamic_params import dynamic_param_lookup
 | 
						|
        param = self._get_param_node()
 | 
						|
        values = dynamic_param_lookup(self.function_value, param.position_index)
 | 
						|
        if values:
 | 
						|
            return values
 | 
						|
 | 
						|
        if param.star_count == 1:
 | 
						|
            from jedi.inference.value.iterable import FakeTuple
 | 
						|
            value = FakeTuple(self.function_value.inference_state, [])
 | 
						|
        elif param.star_count == 2:
 | 
						|
            from jedi.inference.value.iterable import FakeDict
 | 
						|
            value = FakeDict(self.function_value.inference_state, {})
 | 
						|
        elif param.default is None:
 | 
						|
            return NO_VALUES
 | 
						|
        else:
 | 
						|
            return self.function_value.parent_context.infer_node(param.default)
 | 
						|
        return ValueSet({value})
 | 
						|
 | 
						|
 | 
						|
class ParamName(_ActualTreeParamName):
 | 
						|
    def __init__(self, function_value, tree_name, arguments):
 | 
						|
        super().__init__(function_value, tree_name)
 | 
						|
        self.arguments = arguments
 | 
						|
 | 
						|
    def infer(self):
 | 
						|
        values = super().infer()
 | 
						|
        if values:
 | 
						|
            return values
 | 
						|
 | 
						|
        return self.get_executed_param_name().infer()
 | 
						|
 | 
						|
    def get_executed_param_name(self):
 | 
						|
        from jedi.inference.param import get_executed_param_names
 | 
						|
        params_names = get_executed_param_names(self.function_value, self.arguments)
 | 
						|
        return params_names[self._get_param_node().position_index]
 | 
						|
 | 
						|
 | 
						|
class ParamNameWrapper(_ParamMixin):
 | 
						|
    def __init__(self, param_name):
 | 
						|
        self._wrapped_param_name = param_name
 | 
						|
 | 
						|
    def __getattr__(self, name):
 | 
						|
        return getattr(self._wrapped_param_name, name)
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return '<%s: %s>' % (self.__class__.__name__, self._wrapped_param_name)
 | 
						|
 | 
						|
 | 
						|
class ImportName(AbstractNameDefinition):
 | 
						|
    start_pos = (1, 0)
 | 
						|
    _level = 0
 | 
						|
 | 
						|
    def __init__(self, parent_context, string_name):
 | 
						|
        self._from_module_context = parent_context
 | 
						|
        self.string_name = string_name
 | 
						|
 | 
						|
    def get_qualified_names(self, include_module_names=False):
 | 
						|
        if include_module_names:
 | 
						|
            if self._level:
 | 
						|
                assert self._level == 1, "Everything else is not supported for now"
 | 
						|
                module_names = self._from_module_context.string_names
 | 
						|
                if module_names is None:
 | 
						|
                    return module_names
 | 
						|
                return module_names + (self.string_name,)
 | 
						|
            return (self.string_name,)
 | 
						|
        return ()
 | 
						|
 | 
						|
    @property
 | 
						|
    def parent_context(self):
 | 
						|
        m = self._from_module_context
 | 
						|
        import_values = self.infer()
 | 
						|
        if not import_values:
 | 
						|
            return m
 | 
						|
        # It's almost always possible to find the import or to not find it. The
 | 
						|
        # importing returns only one value, pretty much always.
 | 
						|
        return next(iter(import_values)).as_context()
 | 
						|
 | 
						|
    @memoize_method
 | 
						|
    def infer(self):
 | 
						|
        from jedi.inference.imports import Importer
 | 
						|
        m = self._from_module_context
 | 
						|
        return Importer(m.inference_state, [self.string_name], m, level=self._level).follow()
 | 
						|
 | 
						|
    def goto(self):
 | 
						|
        return [m.name for m in self.infer()]
 | 
						|
 | 
						|
    @property
 | 
						|
    def api_type(self):
 | 
						|
        return 'module'
 | 
						|
 | 
						|
    def py__doc__(self):
 | 
						|
        return _merge_name_docs(self.goto())
 | 
						|
 | 
						|
 | 
						|
class SubModuleName(ImportName):
 | 
						|
    _level = 1
 | 
						|
 | 
						|
 | 
						|
class NameWrapper:
 | 
						|
    def __init__(self, wrapped_name):
 | 
						|
        self._wrapped_name = wrapped_name
 | 
						|
 | 
						|
    def __getattr__(self, name):
 | 
						|
        return getattr(self._wrapped_name, name)
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return '%s(%s)' % (self.__class__.__name__, self._wrapped_name)
 | 
						|
 | 
						|
 | 
						|
class StubNameMixin:
 | 
						|
    def py__doc__(self):
 | 
						|
        from jedi.inference.gradual.conversion import convert_names
 | 
						|
        # Stubs are not complicated and we can just follow simple statements
 | 
						|
        # that have an equals in them, because they typically make something
 | 
						|
        # else public. See e.g. stubs for `requests`.
 | 
						|
        names = [self]
 | 
						|
        if self.api_type == 'statement' and '=' in self.tree_name.get_definition().children:
 | 
						|
            names = [v.name for v in self.infer()]
 | 
						|
 | 
						|
        names = convert_names(names, prefer_stub_to_compiled=False)
 | 
						|
        if self in names:
 | 
						|
            return super().py__doc__()
 | 
						|
        else:
 | 
						|
            # We have signatures ourselves in stubs, so don't use signatures
 | 
						|
            # from the implementation.
 | 
						|
            return _merge_name_docs(names)
 | 
						|
 | 
						|
 | 
						|
# From here on down we make looking up the sys.version_info fast.
 | 
						|
class StubName(StubNameMixin, TreeNameDefinition):
 | 
						|
    def infer(self):
 | 
						|
        inferred = super().infer()
 | 
						|
        if self.string_name == 'version_info' and self.get_root_context().py__name__() == 'sys':
 | 
						|
            from jedi.inference.gradual.stub_value import VersionInfo
 | 
						|
            return ValueSet(VersionInfo(c) for c in inferred)
 | 
						|
        return inferred
 | 
						|
 | 
						|
 | 
						|
class ModuleName(ValueNameMixin, AbstractNameDefinition):
 | 
						|
    start_pos = 1, 0
 | 
						|
 | 
						|
    def __init__(self, value, name):
 | 
						|
        self._value = value
 | 
						|
        self._name = name
 | 
						|
 | 
						|
    @property
 | 
						|
    def string_name(self):
 | 
						|
        return self._name
 | 
						|
 | 
						|
 | 
						|
class StubModuleName(StubNameMixin, ModuleName):
 | 
						|
    pass
 |