Exemplo n.º 1
0
    def call_signatures(self):
        """
        Return the function object of the call you're currently in.

        E.g. if the cursor is here::

            abs(# <-- cursor is here

        This would return the ``abs`` function. On the other hand::

            abs()# <-- cursor is here

        This would return an empty list..

        :rtype: list of :class:`classes.CallSignature`
        """
        call_signature_details = \
            helpers.get_call_signature_details(self._get_module(), self._pos)
        if call_signature_details is None:
            return []

        with common.scale_speed_settings(settings.scale_call_signatures):
            definitions = helpers.cache_call_signatures(
                self._evaluator,
                call_signature_details.bracket_leaf,
                self._code_lines,
                self._pos
            )
        debug.speed('func_call followed')

        return [classes.CallSignature(self._evaluator, d.name,
                                      call_signature_details.bracket_leaf.start_pos,
                                      call_signature_details.call_index,
                                      call_signature_details.keyword_name_str)
                for d in definitions if hasattr(d, 'py__call__')]
Exemplo n.º 2
0
    def __init__(self, source=None, line=None, column=None, path=None,
                 encoding='utf-8', source_path=None):
        if source_path is not None:
            warnings.warn("Use path instead of source_path.", DeprecationWarning)
            path = source_path

        if source is None:
            with open(path) as f:
                source = f.read()

        lines = source.splitlines() or ['']
        if source and source[-1] == '\n':
            lines.append('')

        self._line = max(len(lines), 1) if line is None else line
        if not (0 < self._line <= len(lines)):
            raise ValueError('`line` parameter is not in a valid range.')

        line_len = len(lines[self._line - 1])
        self._column = line_len if column is None else column
        if not (0 <= self._column <= line_len):
            raise ValueError('`column` parameter is not in a valid range.')

        api_classes._clear_caches()
        debug.reset_time()
        self.source = modules.source_to_unicode(source, encoding)
        self._pos = self._line, self._column
        self._module = modules.ModuleWithCursor(
            path, source=self.source, position=self._pos)
        self._source_path = path
        self.path = None if path is None else os.path.abspath(path)
        debug.speed('init')
Exemplo n.º 3
0
Arquivo: __init__.py Projeto: ABob/vim
    def call_signatures(self):
        """
        Return the function object of the call you're currently in.

        E.g. if the cursor is here::

            abs(# <-- cursor is here

        This would return the ``abs`` function. On the other hand::

            abs()# <-- cursor is here

        This would return ``None``.

        :rtype: list of :class:`classes.CallSignature`
        """
        call_txt, call_index, key_name, start_pos = self._user_context.call_signature()
        if call_txt is None:
            return []

        stmt = self._get_under_cursor_stmt(call_txt, start_pos)
        if stmt is None:
            return []

        with common.scale_speed_settings(settings.scale_call_signatures):
            origins = cache.cache_call_signatures(self._evaluator, stmt,
                                                  self.source, self._pos)
        debug.speed('func_call followed')

        return [classes.CallSignature(self._evaluator, o.name, stmt, call_index, key_name)
                for o in origins if hasattr(o, 'py__call__')]
Exemplo n.º 4
0
    def call_signatures(self):
        """
        Return the function object of the call you're currently in.

        E.g. if the cursor is here::

            abs(# <-- cursor is here

        This would return the ``abs`` function. On the other hand::

            abs()# <-- cursor is here

        This would return ``None``.

        :rtype: list of :class:`api_classes.CallDef`
        """

        call, index = self._func_call_and_param_index()
        if call is None:
            return []

        user_stmt = self._user_stmt()
        with common.scale_speed_settings(settings.scale_call_signatures):
            _callable = lambda: evaluate.follow_call(call)
            origins = cache.cache_call_signatures(_callable, user_stmt)
        debug.speed('func_call followed')

        return [api_classes.CallDef(o, index, call) for o in origins
                if o.isinstance(er.Function, er.Instance, er.Class)]
Exemplo n.º 5
0
    def completions(self):
        """
        Return :class:`classes.Completion` objects. Those objects contain
        information about the completions, more than just names.

        :return: Completion objects, sorted by name and __ comes last.
        :rtype: list of :class:`classes.Completion`
        """
        debug.speed('completions start')
        completion = Completion(
            self._evaluator, self._get_module(), self._code_lines,
            self._pos, self.call_signatures
        )
        completions = completion.completions()

        def iter_import_completions():
            for c in completions:
                tree_name = c._name.tree_name
                if tree_name is None:
                    continue
                definition = tree_name.get_definition()
                if definition is not None \
                        and definition.type in ('import_name', 'import_from'):
                    yield c

        if len(list(iter_import_completions())) > 10:
            # For now disable completions if there's a lot of imports that
            # might potentially be resolved. This is the case for tensorflow
            # and has been fixed for it. This is obviously temporary until we
            # have a better solution.
            self._evaluator.infer_enabled = False

        debug.speed('completions end')
        return completions
Exemplo n.º 6
0
    def call_signatures(self):
        """
        Return the function object of the call you're currently in.

        E.g. if the cursor is here::

            abs(# <-- cursor is here

        This would return the ``abs`` function. On the other hand::

            abs()# <-- cursor is here

        This would return ``None``.

        :rtype: list of :class:`classes.CallSignature`
        """

        user_stmt = self._parser.user_stmt_with_whitespace()
        call, index = helpers.func_call_and_param_index(user_stmt, self._pos)
        if call is None:
            return []

        with common.scale_speed_settings(settings.scale_call_signatures):
            _callable = lambda: self._evaluator.eval_call(call)
            origins = cache.cache_call_signatures(_callable, user_stmt)
        debug.speed('func_call followed')

        return [classes.CallSignature(self._evaluator, o, call, index) for o in origins
                if o.isinstance(er.Function, er.Instance, er.Class)
                or isinstance(o, compiled.CompiledObject) and o.type() != 'module']
Exemplo n.º 7
0
    def function_definition(self):
        """
        Return the function object of the call you're currently in.

        E.g. if the cursor is here::

            abs(# <-- cursor is here

        This would return the ``abs`` function. On the other hand::

            abs()# <-- cursor is here

        This would return ``None``.

        :rtype: :class:`api_classes.CallDef`
        """

        (call, index) = self._func_call_and_param_index()
        if call is None:
            return None

        user_stmt = self._parser.user_stmt
        with common.scale_speed_settings(settings.scale_function_definition):
            _callable = lambda: evaluate.follow_call(call)
            origins = cache.cache_function_definition(_callable, user_stmt)
        debug.speed('func_call followed')

        if len(origins) == 0:
            return None
        # just take entry zero, because we need just one.
        executable = origins[0]

        return api_classes.CallDef(executable, index, call)
Exemplo n.º 8
0
    def __init__(self, source=None, line=None, column=None, path=None,
                 encoding='utf-8', sys_path=None):
        self._orig_path = path
        # An empty path (also empty string) should always result in no path.
        self.path = os.path.abspath(path) if path else None

        if source is None:
            # TODO add a better warning than the traceback!
            with open(path, 'rb') as f:
                source = f.read()

        # TODO do we really want that?
        self._source = python_bytes_to_unicode(source, encoding, errors='replace')
        self._code_lines = split_lines(self._source)
        line = max(len(self._code_lines), 1) if line is None else line
        if not (0 < line <= len(self._code_lines)):
            raise ValueError('`line` parameter is not in a valid range.')

        line_len = len(self._code_lines[line - 1])
        column = line_len if column is None else column
        if not (0 <= column <= line_len):
            raise ValueError('`column` parameter is not in a valid range.')
        self._pos = line, column
        self._path = path

        cache.clear_time_caches()
        debug.reset_time()

        # Load the Python grammar of the current interpreter.
        self._grammar = parso.load_grammar()
        project = Project(sys_path=sys_path)
        self._evaluator = Evaluator(self._grammar, project)
        project.add_script_path(self.path)
        debug.speed('init')
Exemplo n.º 9
0
    def __init__(self, source=None, line=None, column=None, path=None,
                 encoding='utf-8', sys_path=None, environment=None):
        self._orig_path = path
        # An empty path (also empty string) should always result in no path.
        self.path = os.path.abspath(path) if path else None

        if source is None:
            # TODO add a better warning than the traceback!
            with open(path, 'rb') as f:
                source = f.read()

        # Load the Python grammar of the current interpreter.
        self._grammar = parso.load_grammar()

        if sys_path is not None and not is_py3:
            sys_path = list(map(force_unicode, sys_path))

        # Load the Python grammar of the current interpreter.
        project = get_default_project(
            os.path.dirname(self.path)if path else os.getcwd()
        )
        # TODO deprecate and remove sys_path from the Script API.
        if sys_path is not None:
            project._sys_path = sys_path
        self._evaluator = Evaluator(
            project, environment=environment, script_path=self.path
        )
        debug.speed('init')
        self._module_node, source = self._evaluator.parse_and_get_code(
            code=source,
            path=self.path,
            encoding=encoding,
            cache=False,  # No disk cache, because the current script often changes.
            diff_cache=settings.fast_parser,
            cache_path=settings.cache_directory,
        )
        debug.speed('parsed')
        self._code_lines = parso.split_lines(source, keepends=True)
        self._code = source
        line = max(len(self._code_lines), 1) if line is None else line
        if not (0 < line <= len(self._code_lines)):
            raise ValueError('`line` parameter is not in a valid range.')

        line_string = self._code_lines[line - 1]
        line_len = len(line_string)
        if line_string.endswith('\r\n'):
            line_len -= 1
        if line_string.endswith('\n'):
            line_len -= 1

        column = line_len if column is None else column
        if not (0 <= column <= line_len):
            raise ValueError('`column` parameter (%d) is not in a valid range '
                             '(0-%d) for line %d (%r).' % (
                                 column, line_len, line, line_string))
        self._pos = line, column
        self._path = path

        cache.clear_time_caches()
        debug.reset_time()
Exemplo n.º 10
0
    def __init__(self, source=None, line=None, column=None, path=None,
                 encoding='utf-8', source_path=None):
        if source_path is not None:
            warnings.warn("Use path instead of source_path.", DeprecationWarning)
            path = source_path
        self._source_path = path
        self.path = None if path is None else os.path.abspath(path)

        if source is None:
            with open(path) as f:
                source = f.read()

        lines = source.splitlines() or ['']
        if source and source[-1] == '\n':
            lines.append('')
        line = max(len(lines), 1) if line is None else line
        if not (0 < line <= len(lines)):
            raise ValueError('`line` parameter is not in a valid range.')

        line_len = len(lines[line - 1])
        column = line_len if column is None else column
        if not (0 <= column <= line_len):
            raise ValueError('`column` parameter is not in a valid range.')
        self._pos = line, column

        cache.clear_caches()
        debug.reset_time()
        self.source = common.source_to_unicode(source, encoding)
        self._user_context = UserContext(self.source, self._pos)
        self._parser = UserContextParser(self.source, path, self._pos, self._user_context)
        self._evaluator = Evaluator()
        debug.speed('init')
Exemplo n.º 11
0
    def call_signatures(self):
        """
        Return the function object of the call you're currently in.

        E.g. if the cursor is here::

            abs(# <-- cursor is here

        This would return the ``abs`` function. On the other hand::

            abs()# <-- cursor is here

        This would return ``None``.

        :rtype: list of :class:`classes.CallSignature`
        """
        user_stmt = self._parser.user_stmt_with_whitespace()
        call, index = search_call_signatures(user_stmt, self._pos)
        if call is None:
            return []

        with common.scale_speed_settings(settings.scale_call_signatures):
            _callable = lambda: self._evaluator.eval_call(call)
            origins = cache.cache_call_signatures(_callable, self.source,
                                                  self._pos, user_stmt)
            origins = self._evaluator.eval_call(call)
        debug.speed('func_call followed')

        return [classes.CallSignature(self._evaluator, o, call, index)
                for o in origins if o.is_callable()]
Exemplo n.º 12
0
def func_call_and_param_index(user_stmt, position):
    debug.speed('func_call start')
    call, index = None, 0
    if call is None:
        if user_stmt is not None and isinstance(user_stmt, pr.Statement):
            call, index, _ = helpers.search_call_signatures(user_stmt, position)
    debug.speed('func_call parsed')
    return call, index
Exemplo n.º 13
0
 def _func_call_and_param_index(self):
     debug.speed("func_call start")
     call, index = None, 0
     if call is None:
         user_stmt = self._parser.user_stmt
         if user_stmt is not None and isinstance(user_stmt, pr.Statement):
             call, index, _ = helpers.search_function_definition(user_stmt, self.pos)
     debug.speed("func_call parsed")
     return call, index
Exemplo n.º 14
0
 def __init__(self, source, line, column, source_path, source_encoding="utf-8"):
     api_classes._clear_caches()
     debug.reset_time()
     self.source = modules.source_to_unicode(source, source_encoding)
     self.pos = line, column
     self._module = modules.ModuleWithCursor(source_path, source=self.source, position=self.pos)
     self._source_path = source_path
     self.source_path = None if source_path is None else os.path.abspath(source_path)
     debug.speed("init")
Exemplo n.º 15
0
 def _func_call_and_param_index(self):
     debug.speed('func_call start')
     call, index = None, 0
     if call is None:
         user_stmt = self._user_stmt()
         if user_stmt is not None and isinstance(user_stmt, pr.Statement):
             call, index, _ = helpers.search_call_signatures(user_stmt, self._pos)
     debug.speed('func_call parsed')
     return call, index
Exemplo n.º 16
0
    def __init__(self, evaluator, import_path, module_context, level=0):
        """
        An implementation similar to ``__import__``. Use `follow`
        to actually follow the imports.

        *level* specifies whether to use absolute or relative imports. 0 (the
        default) means only perform absolute imports. Positive values for level
        indicate the number of parent directories to search relative to the
        directory of the module calling ``__import__()`` (see PEP 328 for the
        details).

        :param import_path: List of namespaces (strings or Names).
        """
        debug.speed('import %s' % (import_path,))
        self._evaluator = evaluator
        self.level = level
        self.module_context = module_context
        try:
            self.file_path = module_context.py__file__()
        except AttributeError:
            # Can be None for certain compiled modules like 'builtins'.
            self.file_path = None

        if level:
            base = module_context.py__package__().split('.')
            if base == ['']:
                base = []
            if level > len(base):
                path = module_context.py__file__()
                if path is not None:
                    import_path = list(import_path)
                    p = path
                    for i in range(level):
                        p = os.path.dirname(p)
                    dir_name = os.path.basename(p)
                    # This is not the proper way to do relative imports. However, since
                    # Jedi cannot be sure about the entry point, we just calculate an
                    # absolute path here.
                    if dir_name:
                        # TODO those sys.modules modifications are getting
                        # really stupid. this is the 3rd time that we're using
                        # this. We should probably refactor.
                        if path.endswith(os.path.sep + 'os.py'):
                            import_path.insert(0, 'os')
                        else:
                            import_path.insert(0, dir_name)
                    else:
                        _add_error(module_context, import_path[-1])
                        import_path = []
                        # TODO add import error.
                        debug.warning('Attempted relative import beyond top-level package.')
            else:
                # Here we basically rewrite the level to 0.
                import_path = tuple(base) + tuple(import_path)
        self.import_path = import_path
Exemplo n.º 17
0
    def _user_stmt(self, is_completion=False):
        user_stmt = self._parser.user_stmt
        debug.speed('parsed')

        if is_completion and not user_stmt:
            # for statements like `from x import ` (cursor not in statement)
            pos = next(self._module.get_context(yield_positions=True))
            last_stmt = pos and self._parser.module.get_statement_for_position(
                                pos, include_imports=True)
            if isinstance(last_stmt, pr.Import):
                user_stmt = last_stmt
        return user_stmt
Exemplo n.º 18
0
    def __init__(self,
                 source=None,
                 line=None,
                 column=None,
                 path=None,
                 encoding='utf-8',
                 source_path=None,
                 source_encoding=None,
                 sys_path=None):
        if source_path is not None:
            warnings.warn("Use path instead of source_path.",
                          DeprecationWarning)
            path = source_path
        if source_encoding is not None:
            warnings.warn("Use encoding instead of source_encoding.",
                          DeprecationWarning)
            encoding = source_encoding

        self._orig_path = path
        # An empty path (also empty string) should always result in no path.
        self.path = os.path.abspath(path) if path else None

        if source is None:
            # TODO add a better warning than the traceback!
            try:
                with open(path) as f:
                    source = f.read()
            except UnicodeDecodeError:
                with open(path, encoding=encoding) as f:
                    source = f.read()

        self._source = common.source_to_unicode(source, encoding)
        self._code_lines = common.splitlines(self._source)
        line = max(len(self._code_lines), 1) if line is None else line
        if not (0 < line <= len(self._code_lines)):
            raise ValueError('`line` parameter is not in a valid range.')

        line_len = len(self._code_lines[line - 1])
        column = line_len if column is None else column
        if not (0 <= column <= line_len):
            raise ValueError('`column` parameter is not in a valid range.')
        self._pos = line, column
        self._path = path

        cache.clear_time_caches()
        debug.reset_time()
        self._grammar = load_grammar(version='%s.%s' % sys.version_info[:2])
        if sys_path is None:
            venv = os.getenv('VIRTUAL_ENV')
            if venv:
                sys_path = list(get_venv_path(venv))
        self._evaluator = Evaluator(self._grammar, sys_path=sys_path)
        debug.speed('init')
Exemplo n.º 19
0
    def completions(self):
        """
        Return :class:`classes.Completion` objects. Those objects contain
        information about the completions, more than just names.

        :return: Completion objects, sorted by name and __ comes last.
        :rtype: list of :class:`classes.Completion`
        """
        debug.speed("completions start")
        completion = Completion(self._evaluator, self._get_module(), self._code_lines, self._pos, self.call_signatures)
        completions = completion.completions()
        debug.speed("completions end")
        return completions
Exemplo n.º 20
0
    def call_signatures(self):
        """
        Return the function object of the call you're currently in.

        E.g. if the cursor is here::

            abs(# <-- cursor is here

        This would return the ``abs`` function. On the other hand::

            abs()# <-- cursor is here

        This would return ``None``.

        :rtype: list of :class:`classes.CallSignature`
        """
        user_stmt = self._parser.user_stmt_with_whitespace()
        call, index = search_call_signatures(user_stmt, self._pos)
        if call is None:
            return []

        stmt_el = call
        while isinstance(stmt_el.parent, pr.StatementElement):
            # Go to parent literal/variable until not possible anymore. This
            # makes it possible to return the whole expression.
            stmt_el = stmt_el.parent
        # We can reset the execution since it's a new object
        # (fast_parent_copy).
        execution_arr, call.execution = call.execution, None

        with common.scale_speed_settings(settings.scale_call_signatures):
            _callable = lambda: self._evaluator.eval_call(stmt_el)
            origins = cache.cache_call_signatures(_callable, self.source,
                                                  self._pos, user_stmt)
            origins = self._evaluator.eval_call(stmt_el)
        debug.speed('func_call followed')

        key_name = None
        try:
            detail = execution_arr[index].assignment_details[0]
        except IndexError:
            pass
        else:
            try:
                key_name = unicode(detail[0][0].name)
            except (IndexError, AttributeError):
                pass
        return [classes.CallSignature(self._evaluator, o, call, index, key_name)
                for o in origins if o.is_callable()]
Exemplo n.º 21
0
def search_call_signatures(user_stmt, position):
    """
    Returns the function Call that matches the position before.
    """
    debug.speed('func_call start')
    call, index = None, 0
    if user_stmt is not None and isinstance(user_stmt, pr.Statement):
        # some parts will of the statement will be removed
        user_stmt = fast_parent_copy(user_stmt)
        arr, index = call_signature_array_for_pos(user_stmt, position)
        if arr is not None:
            call = arr.parent

    debug.speed('func_call parsed')
    return call, index
Exemplo n.º 22
0
    def completions(self):
        """
        Return :class:`classes.Completion` objects. Those objects contain
        information about the completions, more than just names.

        :return: Completion objects, sorted by name and __ comes last.
        :rtype: list of :class:`classes.Completion`
        """
        debug.speed('completions start')
        completion = Completion(self._evaluator, self._get_module(),
                                self._code_lines, self._pos,
                                self.call_signatures)
        completions = completion.completions()
        debug.speed('completions end')
        return completions
Exemplo n.º 23
0
def search_call_signatures(user_stmt, position):
    """
    Returns the function Call that matches the position before.
    """
    debug.speed('func_call start')
    call, index = None, 0
    if user_stmt is not None and isinstance(user_stmt, pr.Statement):
        # some parts will of the statement will be removed
        user_stmt = fast_parent_copy(user_stmt)
        arr, index = call_signature_array_for_pos(user_stmt, position)
        if arr is not None:
            call = arr.parent

    debug.speed('func_call parsed')
    return call, index
Exemplo n.º 24
0
    def __init__(self, evaluator, import_path, module_context, level=0):
        """
        An implementation similar to ``__import__``. Use `follow`
        to actually follow the imports.

        *level* specifies whether to use absolute or relative imports. 0 (the
        default) means only perform absolute imports. Positive values for level
        indicate the number of parent directories to search relative to the
        directory of the module calling ``__import__()`` (see PEP 328 for the
        details).

        :param import_path: List of namespaces (strings or Names).
        """
        debug.speed('import %s' % (import_path,))
        self._evaluator = evaluator
        self.level = level
        self.module_context = module_context
        try:
            self.file_path = module_context.py__file__()
        except AttributeError:
            # Can be None for certain compiled modules like 'builtins'.
            self.file_path = None

        if level:
            base = module_context.py__package__().split('.')
            if base == ['']:
                base = []
            if level > len(base):
                path = module_context.py__file__()
                if path is not None:
                    import_path = list(import_path)
                    for i in range(level):
                        path = os.path.dirname(path)
                    dir_name = os.path.basename(path)
                    # This is not the proper way to do relative imports. However, since
                    # Jedi cannot be sure about the entry point, we just calculate an
                    # absolute path here.
                    if dir_name:
                        import_path.insert(0, dir_name)
                    else:
                        _add_error(module_context, import_path[-1])
                        import_path = []
                        # TODO add import error.
                        debug.warning('Attempted relative import beyond top-level package.')
            else:
                # Here we basically rewrite the level to 0.
                import_path = tuple(base) + tuple(import_path)
        self.import_path = import_path
Exemplo n.º 25
0
    def call_signatures(self):
        """
        Return the function object of the call you're currently in.

        E.g. if the cursor is here::

            abs(# <-- cursor is here

        This would return the ``abs`` function. On the other hand::

            abs()# <-- cursor is here

        This would return ``None``.

        :rtype: list of :class:`classes.CallSignature`
        """
        user_stmt = self._parser.user_stmt_with_whitespace()
        call, index = search_call_signatures(user_stmt, self._pos)
        if call is None:
            return []

        stmt_el = call
        while isinstance(stmt_el.parent, pr.StatementElement):
            # Go to parent literal/variable until not possible anymore. This
            # makes it possible to return the whole expression.
            stmt_el = stmt_el.parent
        # We can reset the execution since it's a new object
        # (fast_parent_copy).
        execution_arr, call.execution = call.execution, None

        with common.scale_speed_settings(settings.scale_call_signatures):
            _callable = lambda: self._evaluator.eval_call(stmt_el)
            origins = cache.cache_call_signatures(_callable, self.source,
                                                  self._pos, user_stmt)
        debug.speed('func_call followed')

        key_name = None
        try:
            detail = execution_arr[index].assignment_details[0]
        except IndexError:
            pass
        else:
            try:
                key_name = unicode(detail[0][0].name)
            except (IndexError, AttributeError):
                pass
        return [classes.CallSignature(self._evaluator, o, call, index, key_name)
                for o in origins if o.is_callable()]
Exemplo n.º 26
0
Arquivo: api.py Projeto: lvh/jedi
    def __init__(self, source, line=None, column=None, source_path=None,
                 source_encoding='utf-8'):
        lines = source.splitlines()
        line = len(lines) if line is None else line
        column = len(lines[-1]) if column is None else column

        api_classes._clear_caches()
        debug.reset_time()
        self.source = modules.source_to_unicode(source, source_encoding)
        self.pos = line, column
        self._module = modules.ModuleWithCursor(
            source_path, source=self.source, position=self.pos)
        self._source_path = source_path
        self.source_path = None if source_path is None \
                                    else os.path.abspath(source_path)
        debug.speed('init')
Exemplo n.º 27
0
    def __init__(self,
                 source=None,
                 line=None,
                 column=None,
                 path=None,
                 encoding='utf-8',
                 source_path=None,
                 source_encoding=None,
                 sys_path=None):
        if source_path is not None:
            warnings.warn("Use path instead of source_path.",
                          DeprecationWarning)
            path = source_path
        if source_encoding is not None:
            warnings.warn("Use encoding instead of source_encoding.",
                          DeprecationWarning)
            encoding = source_encoding

        self._orig_path = path
        self.path = None if path is None else os.path.abspath(path)

        if source is None:
            with open(path) as f:
                source = f.read()

        self._source = common.source_to_unicode(source, encoding)
        self._code_lines = common.splitlines(self._source)
        line = max(len(self._code_lines), 1) if line is None else line
        if not (0 < line <= len(self._code_lines)):
            raise ValueError('`line` parameter is not in a valid range.')

        line_len = len(self._code_lines[line - 1])
        column = line_len if column is None else column
        if not (0 <= column <= line_len):
            raise ValueError('`column` parameter is not in a valid range.')
        self._pos = line, column
        self._path = path

        cache.clear_time_caches()
        debug.reset_time()
        self._grammar = load_grammar(version='%s.%s' % sys.version_info[:2])
        if sys_path is None:
            venv = os.getenv('VIRTUAL_ENV')
            if venv:
                sys_path = list(get_venv_path(venv))
        self._evaluator = Evaluator(self._grammar, sys_path=sys_path)
        debug.speed('init')
Exemplo n.º 28
0
    def __init__(self, evaluator, import_path, module, level=0):
        """
        An implementation similar to ``__import__``. Use `follow`
        to actually follow the imports.

        *level* specifies whether to use absolute or relative imports. 0 (the
        default) means only perform absolute imports. Positive values for level
        indicate the number of parent directories to search relative to the
        directory of the module calling ``__import__()`` (see PEP 328 for the
        details).

        :param import_path: List of namespaces (strings or Names).
        """
        debug.speed("import %s" % (import_path,))
        self._evaluator = evaluator
        self.level = level
        self.module = module
        try:
            self.file_path = module.py__file__()
        except AttributeError:
            # Can be None for certain compiled modules like 'builtins'.
            self.file_path = None

        if level:
            base = module.py__package__().split(".")
            if base == [""]:
                base = []
            if level > len(base):
                path = module.py__file__()
                import_path = list(import_path)
                for i in range(level):
                    path = os.path.dirname(path)
                dir_name = os.path.basename(path)
                # This is not the proper way to do relative imports. However, since
                # Jedi cannot be sure about the entry point, we just calculate an
                # absolute path here.
                if dir_name:
                    import_path.insert(0, dir_name)
                else:
                    _add_error(self._evaluator, import_path[-1])
                    import_path = []
                    # TODO add import error.
                    debug.warning("Attempted relative import beyond top-level package.")
            else:
                # Here we basically rewrite the level to 0.
                import_path = tuple(base) + import_path
        self.import_path = import_path
Exemplo n.º 29
0
    def __init__(self, source=None, line=None, column=None, path=None,
                 encoding='utf-8', sys_path=None, environment=None,
                 _project=None):
        self._orig_path = path
        # An empty path (also empty string) should always result in no path.
        self.path = os.path.abspath(path) if path else None

        if source is None:
            # TODO add a better warning than the traceback!
            with open(path, 'rb') as f:
                source = f.read()

        # Load the Python grammar of the current interpreter.
        self._grammar = parso.load_grammar()

        if sys_path is not None and not is_py3:
            sys_path = list(map(force_unicode, sys_path))

        project = _project
        if project is None:
            # Load the Python grammar of the current interpreter.
            project = get_default_project(
                os.path.dirname(self.path)if path else os.getcwd()
            )
        # TODO deprecate and remove sys_path from the Script API.
        if sys_path is not None:
            project._sys_path = sys_path
        self._inference_state = InferenceState(
            project, environment=environment, script_path=self.path
        )
        debug.speed('init')
        self._module_node, source = self._inference_state.parse_and_get_code(
            code=source,
            path=self.path,
            encoding=encoding,
            use_latest_grammar=path and path.endswith('.pyi'),
            cache=False,  # No disk cache, because the current script often changes.
            diff_cache=settings.fast_parser,
            cache_path=settings.cache_directory,
        )
        debug.speed('parsed')
        self._code_lines = parso.split_lines(source, keepends=True)
        self._code = source
        self._pos = line, column

        cache.clear_time_caches()
        debug.reset_time()
Exemplo n.º 30
0
 def __init__(self,
              source,
              line,
              column,
              source_path,
              source_encoding='utf-8'):
     api_classes._clear_caches()
     debug.reset_time()
     self.source = modules.source_to_unicode(source, source_encoding)
     self.pos = line, column
     self._module = modules.ModuleWithCursor(source_path,
                                             source=self.source,
                                             position=self.pos)
     self._source_path = source_path
     self.source_path = None if source_path is None \
                                 else os.path.abspath(source_path)
     debug.speed('init')
Exemplo n.º 31
0
    def _func_call_and_param_index(self):
        def check_user_stmt(user_stmt):
            if user_stmt is None \
                        or not isinstance(user_stmt, pr.Statement):
                return None, 0

            call, index, stop = helpers.search_function_definition(user_stmt, self.pos)
            return call, index

        def check_cache():
            """ Do the parsing with a part parser, therefore reduce ressource
            costs.
            TODO this is not working with multi-line docstrings, improve.
            """
            if self.source_path is None:
                return None, 0

            try:
                parser = cache.parser_cache[self.source_path].parser
            except KeyError:
                return None, 0
            part_parser = self._module.get_part_parser()
            user_stmt = part_parser.user_stmt
            call, index = check_user_stmt(user_stmt)
            if call:
                old_stmt = parser.module.get_statement_for_position(self.pos)
                if old_stmt is None:
                    return None, 0
                old_call, old_index = check_user_stmt(old_stmt)
                if old_call:
                    # compare repr because that should definitely be the same.
                    # Otherwise the whole thing is out of sync.
                    if repr(old_call) == repr(call):
                        # return the index of the part_parser
                        return old_call, index
            return None, 0

        debug.speed('func_call start')
        call = None
        index = 0
        if settings.use_function_definition_cache:
            call, index = check_cache()
        if call is None:
            call, index = check_user_stmt(self._parser.user_stmt)
        debug.speed('func_call parsed')
        return call, index
Exemplo n.º 32
0
    def __init__(self,
                 source=None,
                 line=None,
                 column=None,
                 path=None,
                 encoding='utf-8',
                 source_path=None,
                 source_encoding=None):
        if source_path is not None:
            warnings.warn("Use path instead of source_path.",
                          DeprecationWarning)
            path = source_path
        if source_encoding is not None:
            warnings.warn("Use encoding instead of source_encoding.",
                          DeprecationWarning)
            encoding = source_encoding

        self._orig_path = path
        self.path = None if path is None else os.path.abspath(path)

        if source is None:
            with open(path) as f:
                source = f.read()

        lines = source.splitlines() or ['']
        if source and source[-1] == '\n':
            lines.append('')
        line = max(len(lines), 1) if line is None else line
        if not (0 < line <= len(lines)):
            raise ValueError('`line` parameter is not in a valid range.')

        line_len = len(lines[line - 1])
        column = line_len if column is None else column
        if not (0 <= column <= line_len):
            raise ValueError('`column` parameter is not in a valid range.')
        self._pos = line, column

        cache.clear_caches()
        debug.reset_time()
        self.source = common.source_to_unicode(source, encoding)
        self._user_context = UserContext(self.source, self._pos)
        self._parser = UserContextParser(self.source, path, self._pos,
                                         self._user_context)
        self._evaluator = Evaluator()
        debug.speed('init')
Exemplo n.º 33
0
    def __init__(self,
                 source=None,
                 line=None,
                 column=None,
                 path=None,
                 encoding='utf-8',
                 sys_path=None):
        self._orig_path = path
        # An empty path (also empty string) should always result in no path.
        self.path = os.path.abspath(path) if path else None

        if source is None:
            # TODO add a better warning than the traceback!
            with open(path, 'rb') as f:
                source = f.read()

        # Load the Python grammar of the current interpreter.
        self._grammar = parso.load_grammar()
        project = Project(sys_path=sys_path)
        self._evaluator = Evaluator(self._grammar, project)
        self._module_node, source = self._evaluator.parse_and_get_code(
            code=source,
            path=self.path,
            cache=
            False,  # No disk cache, because the current script often changes.
            diff_cache=True,
            cache_path=settings.cache_directory)
        self._code_lines = split_lines(source)
        line = max(len(self._code_lines), 1) if line is None else line
        if not (0 < line <= len(self._code_lines)):
            raise ValueError('`line` parameter is not in a valid range.')

        line_len = len(self._code_lines[line - 1])
        column = line_len if column is None else column
        if not (0 <= column <= line_len):
            raise ValueError('`column` parameter is not in a valid range.')
        self._pos = line, column
        self._path = path

        cache.clear_time_caches()
        debug.reset_time()

        project.add_script_path(self.path)
        debug.speed('init')
Exemplo n.º 34
0
    def __init__(self,
                 code=None,
                 *,
                 path=None,
                 environment=None,
                 project=None):
        self._orig_path = path
        if isinstance(path, str):
            path = Path(path)

        self.path = path.absolute() if path else None

        if code is None:
            if path is None:
                raise ValueError("Must provide at least one of code or path")

            # TODO add a better warning than the traceback!
            with open(path, 'rb') as f:
                code = f.read()

        if project is None:
            # Load the Python grammar of the current interpreter.
            project = get_default_project(
                None if self.path is None else self.path.parent)

        self._inference_state = InferenceState(project,
                                               environment=environment,
                                               script_path=self.path)
        debug.speed('init')
        self._module_node, code = self._inference_state.parse_and_get_code(
            code=code,
            path=self.path,
            use_latest_grammar=path and path.suffix == '.pyi',
            cache=
            False,  # No disk cache, because the current script often changes.
            diff_cache=settings.fast_parser,
            cache_path=settings.cache_directory,
        )
        debug.speed('parsed')
        self._code_lines = parso.split_lines(code, keepends=True)
        self._code = code

        cache.clear_time_caches()
        debug.reset_time()
Exemplo n.º 35
0
    def __init__(self,
                 source=None,
                 line=None,
                 column=None,
                 path=None,
                 encoding='utf-8',
                 sys_path=None):
        self._orig_path = path
        # An empty path (also empty string) should always result in no path.
        self.path = os.path.abspath(path) if path else None

        if source is None:
            # TODO add a better warning than the traceback!
            with open(path, 'rb') as f:
                source = f.read()

        # TODO do we really want that?
        self._source = python_bytes_to_unicode(source,
                                               encoding,
                                               errors='replace')
        self._code_lines = split_lines(self._source)
        line = max(len(self._code_lines), 1) if line is None else line
        if not (0 < line <= len(self._code_lines)):
            raise ValueError('`line` parameter is not in a valid range.')

        line_len = len(self._code_lines[line - 1])
        column = line_len if column is None else column
        if not (0 <= column <= line_len):
            raise ValueError('`column` parameter is not in a valid range.')
        self._pos = line, column
        self._path = path

        cache.clear_time_caches()
        debug.reset_time()

        # Load the Python grammar of the current interpreter.
        self._grammar = parso.load_grammar()
        if sys_path is None:
            venv = os.getenv('VIRTUAL_ENV')
            if venv:
                sys_path = list(get_venv_path(venv))
        self._evaluator = Evaluator(self._grammar, sys_path=sys_path)
        debug.speed('init')
Exemplo n.º 36
0
    def __init__(self, source=None, line=None, column=None, path=None,
                 encoding='utf-8', source_path=None, source_encoding=None,
                 sys_path=None):
        if source_path is not None:
            warnings.warn("Use path instead of source_path.", DeprecationWarning)
            path = source_path
        if source_encoding is not None:
            warnings.warn("Use encoding instead of source_encoding.", DeprecationWarning)
            encoding = source_encoding

        self._orig_path = path
        self.path = None if path is None else os.path.abspath(path)

        if source is None:
            with open(path) as f:
                source = f.read()

        self.source = common.source_to_unicode(source, encoding)
        lines = common.splitlines(self.source)
        line = max(len(lines), 1) if line is None else line
        if not (0 < line <= len(lines)):
            raise ValueError('`line` parameter is not in a valid range.')

        line_len = len(lines[line - 1])
        column = line_len if column is None else column
        if not (0 <= column <= line_len):
            raise ValueError('`column` parameter is not in a valid range.')
        self._pos = line, column

        cache.clear_time_caches()
        debug.reset_time()
        self._grammar = load_grammar('grammar%s.%s' % sys.version_info[:2])
        self._user_context = UserContext(self.source, self._pos)
        self._parser = UserContextParser(self._grammar, self.source, path,
                                         self._pos, self._user_context,
                                         self._parsed_callback)
        if sys_path is None:
            venv = os.getenv('VIRTUAL_ENV')
            if venv:
                sys_path = list(get_venv_path(venv))
        self._evaluator = Evaluator(self._grammar, sys_path=sys_path)
        debug.speed('init')
Exemplo n.º 37
0
    def _prepare_goto(self, goto_path, is_like_search=False):
        """ Base for complete, goto and definition. Basically it returns
        the resolved scopes under cursor. """
        debug.dbg('start: %s in %s' % (goto_path, self._parser.user_scope))

        user_stmt = self._parser.user_stmt
        debug.speed('parsed')
        if not user_stmt and len(goto_path.split('\n')) > 1:
            # If the user_stmt is not defined and the goto_path is multi line,
            # something's strange. Most probably the backwards tokenizer
            # matched to much.
            return []

        if isinstance(user_stmt, pr.Import):
            scopes = [self._get_on_import_stmt(is_like_search)[0]]
        else:
            # just parse one statement, take it and evaluate it
            stmt = self._get_under_cursor_stmt(goto_path)
            scopes = evaluate.follow_statement(stmt)
        return scopes
Exemplo n.º 38
0
    def __init__(self, source=None, line=None, column=None, path=None,
                 encoding='utf-8', source_path=None, source_encoding=None,
                 sys_path=None):
        if source_path is not None:
            warnings.warn("Deprecated since version 0.7. Use path instead of source_path.", DeprecationWarning, stacklevel=2)
            path = source_path
        if source_encoding is not None:
            warnings.warn("Deprecated since version 0.8. Use encoding instead of source_encoding.", DeprecationWarning, stacklevel=2)
            encoding = source_encoding

        self._orig_path = path
        # An empty path (also empty string) should always result in no path.
        self.path = os.path.abspath(path) if path else None

        if source is None:
            # TODO add a better warning than the traceback!
            with open(path, 'rb') as f:
                source = f.read()

        self._source = common.source_to_unicode(source, encoding)
        self._code_lines = common.splitlines(self._source)
        line = max(len(self._code_lines), 1) if line is None else line
        if not (0 < line <= len(self._code_lines)):
            raise ValueError('`line` parameter is not in a valid range.')

        line_len = len(self._code_lines[line - 1])
        column = line_len if column is None else column
        if not (0 <= column <= line_len):
            raise ValueError('`column` parameter is not in a valid range.')
        self._pos = line, column
        self._path = path

        cache.clear_time_caches()
        debug.reset_time()
        self._grammar = load_grammar(version='%s.%s' % sys.version_info[:2])
        if sys_path is None:
            venv = os.getenv('VIRTUAL_ENV')
            if venv:
                sys_path = list(get_venv_path(venv))
        self._evaluator = Evaluator(self._grammar, sys_path=sys_path)
        debug.speed('init')
Exemplo n.º 39
0
    def __init__(self, source=None, line=None, column=None, path=None,
                 encoding='utf-8', source_path=None, source_encoding=None):
        if source_path is not None:
            warnings.warn("Use path instead of source_path.", DeprecationWarning)
            path = source_path
        if source_encoding is not None:
            warnings.warn("Use encoding instead of source_encoding.", DeprecationWarning)
            encoding = source_encoding

        self._orig_path = path
        self.path = None if path is None else os.path.abspath(path)

        if source is None:
            try:
                with open(path) as f:
                    source = f.read()
            except UnicodeDecodeError:
                with open(path, encoding=encoding) as f:
                    source = f.read()

        self.source = common.source_to_unicode(source, encoding)
        lines = common.splitlines(self.source)
        line = max(len(lines), 1) if line is None else line
        if not (0 < line <= len(lines)):
            raise ValueError('`line` parameter is not in a valid range.')

        line_len = len(lines[line - 1])
        column = line_len if column is None else column
        if not (0 <= column <= line_len):
            raise ValueError('`column` parameter is not in a valid range.')
        self._pos = line, column

        cache.clear_time_caches()
        debug.reset_time()
        self._grammar = load_grammar('grammar%s.%s' % sys.version_info[:2])
        self._user_context = UserContext(self.source, self._pos)
        self._parser = UserContextParser(self._grammar, self.source, path,
                                         self._pos, self._user_context,
                                         self._parsed_callback)
        self._evaluator = Evaluator(self._grammar)
        debug.speed('init')
Exemplo n.º 40
0
    def call_signatures(self):
        """
        Return the function object of the call you're currently in.

        E.g. if the cursor is here::

            abs(# <-- cursor is here

        This would return the ``abs`` function. On the other hand::

            abs()# <-- cursor is here

        This would return an empty list..

        :rtype: list of :class:`classes.CallSignature`
        """
        call_signature_details = \
            helpers.get_call_signature_details(self._module_node, self._pos)
        if call_signature_details is None:
            return []

        context = self._evaluator.create_context(
            self._get_module(),
            call_signature_details.bracket_leaf
        )
        definitions = helpers.cache_call_signatures(
            self._evaluator,
            context,
            call_signature_details.bracket_leaf,
            self._code_lines,
            self._pos
        )
        debug.speed('func_call followed')

        # TODO here we use stubs instead of the actual contexts. We should use
        # the signatures from stubs, but the actual contexts, probably?!
        return [classes.CallSignature(self._evaluator, signature,
                                      call_signature_details.bracket_leaf.start_pos,
                                      call_signature_details.call_index,
                                      call_signature_details.keyword_name_str)
                for signature in definitions.get_signatures()]
Exemplo n.º 41
0
    def __init__(self, evaluator, import_path, module, level=0):
        """
        An implementation similar to ``__import__``. Use `follow_file_system`
        to actually follow the imports.

        *level* specifies whether to use absolute or relative imports. 0 (the
        default) means only perform absolute imports. Positive values for level
        indicate the number of parent directories to search relative to the
        directory of the module calling ``__import__()`` (see PEP 328 for the
        details).

        :param import_path: List of namespaces (strings).
        """
        debug.speed('import %s' % (import_path, ))
        self._evaluator = evaluator
        self.import_path = import_path
        self.level = level
        self.module = module
        path = module.path
        # TODO abspath
        self.file_path = os.path.dirname(path) if path is not None else None
Exemplo n.º 42
0
    def __init__(self, evaluator, import_path, module, level=0):
        """
        An implementation similar to ``__import__``. Use `follow_file_system`
        to actually follow the imports.

        *level* specifies whether to use absolute or relative imports. 0 (the
        default) means only perform absolute imports. Positive values for level
        indicate the number of parent directories to search relative to the
        directory of the module calling ``__import__()`` (see PEP 328 for the
        details).

        :param import_path: List of namespaces (strings).
        """
        debug.speed('import %s' % (import_path,))
        self._evaluator = evaluator
        self.import_path = import_path
        self.level = level
        self.module = module
        path = module.path
        # TODO abspath
        self.file_path = os.path.dirname(path) if path is not None else None
Exemplo n.º 43
0
    def call_signatures(self):
        """
        Return the function object of the call you're currently in.

        E.g. if the cursor is here::

            abs(# <-- cursor is here

        This would return the ``abs`` function. On the other hand::

            abs()# <-- cursor is here

        This would return an empty list..

        :rtype: list of :class:`classes.CallSignature`
        """
        call_signature_details = \
            helpers.get_call_signature_details(self._get_module_node(), self._pos)
        if call_signature_details is None:
            return []

        context = self._evaluator.create_context(
            self._get_module(),
            call_signature_details.bracket_leaf
        )
        with common.scale_speed_settings(settings.scale_call_signatures):
            definitions = helpers.cache_call_signatures(
                self._evaluator,
                context,
                call_signature_details.bracket_leaf,
                self._code_lines,
                self._pos
            )
        debug.speed('func_call followed')

        return [classes.CallSignature(self._evaluator, d.name,
                                      call_signature_details.bracket_leaf.start_pos,
                                      call_signature_details.call_index,
                                      call_signature_details.keyword_name_str)
                for d in definitions if hasattr(d, 'py__call__')]
Exemplo n.º 44
0
    def __init__(self, source, line=None, column=None, path=None,
                 source_encoding='utf-8', source_path=None):
        if source_path is not None:
            warnings.warn("Use path instead of source_path.", DeprecationWarning)
            path = source_path

        lines = source.splitlines()
        if source and source[-1] == '\n':
            lines.append('')

        self._line = max(len(lines), 1) if line is None else line
        self._column = len(lines[-1]) if column is None else column

        api_classes._clear_caches()
        debug.reset_time()
        self.source = modules.source_to_unicode(source, source_encoding)
        self.pos = self._line, self._column
        self._module = modules.ModuleWithCursor(
            path, source=self.source, position=self.pos)
        self._source_path = path
        self.path = None if path is None else os.path.abspath(path)
        debug.speed('init')
Exemplo n.º 45
0
Arquivo: api.py Projeto: rayleyva/jedi
    def __init__(self,
                 source=None,
                 line=None,
                 column=None,
                 path=None,
                 source_encoding='utf-8',
                 source_path=None):
        if source_path is not None:
            warnings.warn("Use path instead of source_path.",
                          DeprecationWarning)
            path = source_path

        if source is None:
            with open(path) as f:
                source = f.read()

        lines = source.splitlines() or ['']
        if source and source[-1] == '\n':
            lines.append('')

        self._line = max(len(lines), 1) if line is None else line
        if not (0 < self._line <= len(lines)):
            raise ValueError('`line` parameter is not in a valid range.')

        line_len = len(lines[self._line - 1])
        self._column = line_len if column is None else column
        if not (0 <= self._column <= line_len):
            raise ValueError('`column` parameter is not in a valid range.')

        api_classes._clear_caches()
        debug.reset_time()
        self.source = modules.source_to_unicode(source, source_encoding)
        self._pos = self._line, self._column
        self._module = modules.ModuleWithCursor(path,
                                                source=self.source,
                                                position=self._pos)
        self._source_path = path
        self.path = None if path is None else os.path.abspath(path)
        debug.speed('init')
Exemplo n.º 46
0
def search_call_signatures(user_stmt, position):
    """
    Returns the function Call that matches the position before.
    """
    debug.speed('func_call start')
    call, index = None, 0
    if user_stmt is not None and isinstance(user_stmt, pr.Statement):
        # some parts will of the statement will be removed
        user_stmt = fast_parent_copy(user_stmt)
        arr, index = call_signature_array_for_pos(user_stmt, position)
        if arr is not None:
            call = arr.parent
            while isinstance(call.parent, pr.StatementElement):
                # Go to parent literal/variable until not possible anymore. This
                # makes it possible to return the whole expression.
                call = call.parent
            arr.parent.execution = None
            if not isinstance(call, pr.Call):
                call = None

    debug.speed('func_call parsed')
    return call, index
Exemplo n.º 47
0
def search_call_signatures(user_stmt, position):
    """
    Returns the function Call that matches the position before.
    """
    debug.speed('func_call start')
    call, arr, index = None, None, 0
    if user_stmt is not None and isinstance(user_stmt, pr.ExprStmt):
        # some parts will of the statement will be removed
        user_stmt = deep_ast_copy(user_stmt)
        arr, index, call = call_signature_array_for_pos(user_stmt, position)

        # Now remove the part after the call. Including the array from the
        # statement.
        stmt_el = call
        while isinstance(stmt_el, pr.StatementElement):
            if stmt_el.next == arr:
                stmt_el.next = None
                break
            stmt_el = stmt_el.next

    debug.speed('func_call parsed')
    return call, arr, index
Exemplo n.º 48
0
    def _prepare_goto(self, goto_path, is_like_search=False):
        """
        Base for completions/goto. Basically it returns the resolved scopes
        under cursor.
        """
        debug.dbg('start: %s in %s' % (goto_path, self._parser.user_scope))

        user_stmt = self._parser.user_stmt
        debug.speed('parsed')
        if not user_stmt and len(goto_path.split('\n')) > 1:
            # If the user_stmt is not defined and the goto_path is multi line,
            # something's strange. Most probably the backwards tokenizer
            # matched to much.
            return []

        if isinstance(user_stmt, pr.Import):
            scopes = [self._get_on_import_stmt(is_like_search)[0]]
        else:
            # just parse one statement, take it and evaluate it
            stmt = self._get_under_cursor_stmt(goto_path)
            scopes = evaluate.follow_statement(stmt)
        return scopes
Exemplo n.º 49
0
    def call_signatures(self):
        """
        Return the function object of the call you're currently in.

        E.g. if the cursor is here::

            abs(# <-- cursor is here

        This would return the ``abs`` function. On the other hand::

            abs()# <-- cursor is here

        This would return ``None``.

        :rtype: list of :class:`classes.CallSignature`
        """
        user_stmt = self._parser.user_stmt_with_whitespace()
        call, execution_arr, index = search_call_signatures(user_stmt, self._pos)
        if call is None:
            return []

        with common.scale_speed_settings(settings.scale_call_signatures):
            origins = cache.cache_call_signatures(self._evaluator, call, self.source,
                                                  self._pos, user_stmt)
        debug.speed('func_call followed')

        key_name = None
        try:
            detail = execution_arr[index].assignment_details[0]
        except IndexError:
            pass
        else:
            try:
                key_name = unicode(detail[0][0].name)
            except (IndexError, AttributeError):
                pass
        return [classes.CallSignature(self._evaluator, o.name, call, index, key_name)
                for o in origins if hasattr(o, 'py__call__')]
Exemplo n.º 50
0
    def __init__(self,
                 code=None,
                 line=None,
                 column=None,
                 path=None,
                 encoding=None,
                 sys_path=None,
                 environment=None,
                 project=None,
                 source=None):
        self._orig_path = path
        # An empty path (also empty string) should always result in no path.
        self.path = os.path.abspath(path) if path else None

        if encoding is None:
            encoding = 'utf-8'
        else:
            warnings.warn(
                "Deprecated since version 0.17.0. You should cast to valid "
                "unicode yourself, especially if you are not using utf-8.",
                DeprecationWarning,
                stacklevel=2)
        if line is not None:
            warnings.warn(
                "Providing the line is now done in the functions themselves "
                "like `Script(...).complete(line, column)`",
                DeprecationWarning,
                stacklevel=2)
        if column is not None:
            warnings.warn(
                "Providing the column is now done in the functions themselves "
                "like `Script(...).complete(line, column)`",
                DeprecationWarning,
                stacklevel=2)
        if source is not None:
            code = source
            warnings.warn("Use the code keyword argument instead.",
                          DeprecationWarning,
                          stacklevel=2)
        if code is None:
            # TODO add a better warning than the traceback!
            with open(path, 'rb') as f:
                code = f.read()

        if sys_path is not None and not is_py3:
            sys_path = list(map(force_unicode, sys_path))

        if project is None:
            # Load the Python grammar of the current interpreter.
            project = get_default_project(
                os.path.dirname(self.path) if path else None)
        # TODO deprecate and remove sys_path from the Script API.
        if sys_path is not None:
            project._sys_path = sys_path
            warnings.warn(
                "Deprecated since version 0.17.0. Use the project API instead, "
                "which means Script(project=Project(dir, sys_path=sys_path)) instead.",
                DeprecationWarning,
                stacklevel=2)

        self._inference_state = InferenceState(project,
                                               environment=environment,
                                               script_path=self.path)
        debug.speed('init')
        self._module_node, code = self._inference_state.parse_and_get_code(
            code=code,
            path=self.path,
            encoding=encoding,
            use_latest_grammar=path and path.endswith('.pyi'),
            cache=
            False,  # No disk cache, because the current script often changes.
            diff_cache=settings.fast_parser,
            cache_path=settings.cache_directory,
        )
        debug.speed('parsed')
        self._code_lines = parso.split_lines(code, keepends=True)
        self._code = code
        self._pos = line, column

        cache.clear_time_caches()
        debug.reset_time()
Exemplo n.º 51
0
def test_simple():
    jedi.set_debug_function()
    debug.speed('foo')
    debug.dbg('bar')
    debug.warning('baz')
    jedi.set_debug_function(None, False, False, False)
Exemplo n.º 52
0
 def user_stmt(self):
     module = self.module()
     debug.speed('parsed')
     return module.get_statement_for_position(self._position)
Exemplo n.º 53
0
    def completions(self):
        """
        Return :class:`classes.Completion` objects. Those objects contain
        information about the completions, more than just names.

        :return: Completion objects, sorted by name and __ comes last.
        :rtype: list of :class:`classes.Completion`
        """
        def get_completions(user_stmt, bs):
            if isinstance(user_stmt, pr.Import):
                context = self._user_context.get_context()
                next(context)  # skip the path
                if next(context) == 'from':
                    # completion is just "import" if before stands from ..
                    return ((k, bs) for k in keywords.keyword_names('import'))
            return self._simple_complete(path, like)

        def completion_possible(path):
            """
            The completion logic is kind of complicated, because we strip the
            last word part. To ignore certain strange patterns with dots, just
            use regex.
            """
            if re.match('\d+\.\.$|\.{4}$', path):
                return True  # check Ellipsis and float literal `1.`

            return not re.search(r'^\.|^\d\.$|\.\.$', path)

        debug.speed('completions start')
        path = self._user_context.get_path_until_cursor()
        if not completion_possible(path):
            return []
        path, dot, like = helpers.completion_parts(path)

        user_stmt = self._parser.user_stmt_with_whitespace()
        b = compiled.builtin
        completions = get_completions(user_stmt, b)

        if not dot:
            # add named params
            for call_sig in self.call_signatures():
                # allow protected access, because it's a public API.
                module = call_sig._definition.get_parent_until()
                # Compiled modules typically don't allow keyword arguments.
                if not isinstance(module, compiled.CompiledObject):
                    for p in call_sig.params:
                        # Allow access on _definition here, because it's a
                        # public API and we don't want to make the internal
                        # Name object public.
                        if p._definition.stars == 0:  # no *args/**kwargs
                            completions.append((p._definition.get_name(), p))

            if not path and not isinstance(user_stmt, pr.Import):
                # add keywords
                completions += ((k, b)
                                for k in keywords.keyword_names(all=True))

        needs_dot = not dot and path

        comps = []
        comp_dct = {}
        for c, s in set(completions):
            n = str(c.names[-1])
            if settings.case_insensitive_completion \
                    and n.lower().startswith(like.lower()) \
                    or n.startswith(like):
                if not filter_private_variable(
                        s, user_stmt or self._parser.user_scope(), n):
                    new = classes.Completion(self._evaluator, c, needs_dot,
                                             len(like), s)
                    k = (new.name, new.complete)  # key
                    if k in comp_dct and settings.no_completion_duplicates:
                        comp_dct[k]._same_name_completions.append(new)
                    else:
                        comp_dct[k] = new
                        comps.append(new)

        debug.speed('completions end')

        return sorted(
            comps,
            key=lambda x:
            (x.name.startswith('__'), x.name.startswith('_'), x.name.lower()))
Exemplo n.º 54
0
Arquivo: api.py Projeto: rayleyva/jedi
    def completions(self):
        """
        Return :class:`api_classes.Completion` objects. Those objects contain
        information about the completions, more than just names.

        :return: Completion objects, sorted by name and __ comes last.
        :rtype: list of :class:`api_classes.Completion`
        """
        def get_completions(user_stmt, bs):
            if isinstance(user_stmt, pr.Import):
                context = self._module.get_context()
                next(context)  # skip the path
                if next(context) == 'from':
                    # completion is just "import" if before stands from ..
                    return ((k, bs) for k in keywords.keyword_names('import'))
            return self._simple_complete(path, like)

        debug.speed('completions start')
        path = self._module.get_path_until_cursor()
        if re.search('^\.|\.\.$', path):
            return []
        path, dot, like = self._get_completion_parts()

        user_stmt = self._user_stmt(True)
        bs = builtin.Builtin.scope
        completions = get_completions(user_stmt, bs)

        if not dot:
            # add named params
            for call_def in self.call_signatures():
                if not call_def.module.is_builtin():
                    for p in call_def.params:
                        completions.append((p.get_name(), p))

            if not path and not isinstance(user_stmt, pr.Import):
                # add keywords
                completions += ((k, bs)
                                for k in keywords.keyword_names(all=True))

        needs_dot = not dot and path

        comps = []
        comp_dct = {}
        for c, s in set(completions):
            n = c.names[-1]
            if settings.case_insensitive_completion \
                    and n.lower().startswith(like.lower()) \
                    or n.startswith(like):
                if not evaluate.filter_private_variable(
                        s, user_stmt or self._parser.user_scope, n):
                    new = api_classes.Completion(c, needs_dot, len(like), s)
                    k = (new.name, new.complete)  # key
                    if k in comp_dct and settings.no_completion_duplicates:
                        comp_dct[k]._same_name_completions.append(new)
                    else:
                        comp_dct[k] = new
                        comps.append(new)

        debug.speed('completions end')

        return sorted(
            comps,
            key=lambda x:
            (x.name.startswith('__'), x.name.startswith('_'), x.name.lower()))
Exemplo n.º 55
0
    def __init__(self,
                 source=None,
                 line=None,
                 column=None,
                 path=None,
                 encoding='utf-8',
                 sys_path=None,
                 environment=None):
        self._orig_path = path
        # An empty path (also empty string) should always result in no path.
        self.path = os.path.abspath(path) if path else None

        if source is None:
            # TODO add a better warning than the traceback!
            with open(path, 'rb') as f:
                source = f.read()

        # Load the Python grammar of the current interpreter.
        self._grammar = parso.load_grammar()

        if sys_path is not None and not is_py3:
            sys_path = list(map(force_unicode, sys_path))

        # Load the Python grammar of the current interpreter.
        project = get_default_project(
            os.path.dirname(self.path) if path else os.getcwd())
        # TODO deprecate and remove sys_path from the Script API.
        if sys_path is not None:
            project._sys_path = sys_path
        self._evaluator = Evaluator(project,
                                    environment=environment,
                                    script_path=self.path)
        self._project = project
        debug.speed('init')
        self._module_node, source = self._evaluator.parse_and_get_code(
            code=source,
            path=self.path,
            cache=
            False,  # No disk cache, because the current script often changes.
            diff_cache=True,
            cache_path=settings.cache_directory)
        debug.speed('parsed')
        self._code_lines = parso.split_lines(source, keepends=True)
        self._code = source
        line = max(len(self._code_lines), 1) if line is None else line
        if not (0 < line <= len(self._code_lines)):
            raise ValueError('`line` parameter is not in a valid range.')

        line_string = self._code_lines[line - 1]
        line_len = len(line_string)
        if line_string.endswith('\r\n'):
            line_len -= 1
        if line_string.endswith('\n'):
            line_len -= 1

        column = line_len if column is None else column
        if not (0 <= column <= line_len):
            raise ValueError('`column` parameter is not in a valid range.')
        self._pos = line, column
        self._path = path

        cache.clear_time_caches()
        debug.reset_time()
Exemplo n.º 56
0
 def user_stmt(self):
     module = self.module()
     debug.speed('parsed')
     return module.get_statement_for_position(self._position,
                                              include_imports=True)
Exemplo n.º 57
0
    def completions(self):
        """
        Return :class:`classes.Completion` objects. Those objects contain
        information about the completions, more than just names.

        :return: Completion objects, sorted by name and __ comes last.
        :rtype: list of :class:`classes.Completion`
        """
        def get_completions(user_stmt, bs):
            # TODO this closure is ugly. it also doesn't work with
            # simple_complete (used for Interpreter), somehow redo.
            module = self._evaluator.wrap(self._parser.module())
            names, level, only_modules, unfinished_dotted = \
                helpers.check_error_statements(module, self._pos)
            completion_names = []
            if names is not None:
                imp_names = tuple(
                    str(n) for n in names if n.end_pos < self._pos)
                i = imports.Importer(self._evaluator, imp_names, module, level)
                completion_names = i.completion_names(self._evaluator,
                                                      only_modules)

            # TODO this paragraph is necessary, but not sure it works.
            context = self._user_context.get_context()
            if not next(context).startswith('.'):  # skip the path
                if next(context) == 'from':
                    # completion is just "import" if before stands from ..
                    if unfinished_dotted:
                        return completion_names
                    else:
                        return set([keywords.keyword('import').name])

            if isinstance(user_stmt, tree.Import):
                module = self._parser.module()
                completion_names += imports.completion_names(
                    self._evaluator, user_stmt, self._pos)
                return completion_names

            if names is None and not isinstance(user_stmt, tree.Import):
                if not path and not dot:
                    # add keywords
                    completion_names += keywords.completion_names(
                        self._evaluator, user_stmt, self._pos, module)
                    # TODO delete? We should search for valid parser
                    # transformations.
                completion_names += self._simple_complete(path, dot, like)
            return completion_names

        debug.speed('completions start')
        path = self._user_context.get_path_until_cursor()
        # Dots following an int are not the start of a completion but a float
        # literal.
        if re.search(r'^\d\.$', path):
            return []
        path, dot, like = helpers.completion_parts(path)

        user_stmt = self._parser.user_stmt_with_whitespace()

        b = compiled.builtin
        completion_names = get_completions(user_stmt, b)

        if not dot:
            # add named params
            for call_sig in self.call_signatures():
                # Allow protected access, because it's a public API.
                module = call_sig._name.get_parent_until()
                # Compiled modules typically don't allow keyword arguments.
                if not isinstance(module, compiled.CompiledObject):
                    for p in call_sig.params:
                        # Allow access on _definition here, because it's a
                        # public API and we don't want to make the internal
                        # Name object public.
                        if p._definition.stars == 0:  # no *args/**kwargs
                            completion_names.append(p._name)

        needs_dot = not dot and path

        comps = []
        comp_dct = {}
        for c in set(completion_names):
            n = str(c)
            if settings.case_insensitive_completion \
                    and n.lower().startswith(like.lower()) \
                    or n.startswith(like):
                if isinstance(c.parent, (tree.Function, tree.Class)):
                    # TODO I think this is a hack. It should be an
                    #   er.Function/er.Class before that.
                    c = self._evaluator.wrap(c.parent).name
                new = classes.Completion(self._evaluator, c, needs_dot,
                                         len(like))
                k = (new.name, new.complete)  # key
                if k in comp_dct and settings.no_completion_duplicates:
                    comp_dct[k]._same_name_completions.append(new)
                else:
                    comp_dct[k] = new
                    comps.append(new)

        debug.speed('completions end')

        return sorted(
            comps,
            key=lambda x:
            (x.name.startswith('__'), x.name.startswith('_'), x.name.lower()))
Exemplo n.º 58
0
    def __init__(self, inference_state, import_path, module_context, level=0):
        """
        An implementation similar to ``__import__``. Use `follow`
        to actually follow the imports.

        *level* specifies whether to use absolute or relative imports. 0 (the
        default) means only perform absolute imports. Positive values for level
        indicate the number of parent directories to search relative to the
        directory of the module calling ``__import__()`` (see PEP 328 for the
        details).

        :param import_path: List of namespaces (strings or Names).
        """
        debug.speed('import %s %s' % (import_path, module_context))
        self._inference_state = inference_state
        self.level = level
        self._module_context = module_context

        self._fixed_sys_path = None
        self._infer_possible = True
        if level:
            base = module_context.get_value().py__package__()
            # We need to care for two cases, the first one is if it's a valid
            # Python import. This import has a properly defined module name
            # chain like `foo.bar.baz` and an import in baz is made for
            # `..lala.` It can then resolve to `foo.bar.lala`.
            # The else here is a heuristic for all other cases, if for example
            # in `foo` you search for `...bar`, it's obviously out of scope.
            # However since Jedi tries to just do it's best, we help the user
            # here, because he might have specified something wrong in his
            # project.
            if level <= len(base):
                # Here we basically rewrite the level to 0.
                base = tuple(base)
                if level > 1:
                    base = base[:-level + 1]
                import_path = base + tuple(import_path)
            else:
                path = module_context.py__file__()
                project_path = self._inference_state.project.path
                import_path = list(import_path)
                if path is None:
                    # If no path is defined, our best guess is that the current
                    # file is edited by a user on the current working
                    # directory. We need to add an initial path, because it
                    # will get removed as the name of the current file.
                    directory = project_path
                else:
                    directory = os.path.dirname(path)

                base_import_path, base_directory = _level_to_base_import_path(
                    project_path, directory, level,
                )
                if base_directory is None:
                    # Everything is lost, the relative import does point
                    # somewhere out of the filesystem.
                    self._infer_possible = False
                else:
                    self._fixed_sys_path = [base_directory]

                if base_import_path is None:
                    if import_path:
                        _add_error(
                            module_context, import_path[0],
                            message='Attempted relative import beyond top-level package.'
                        )
                else:
                    import_path = base_import_path + import_path
        self.import_path = import_path
Exemplo n.º 59
0
    def __init__(self, evaluator, import_path, module_context, level=0):
        """
        An implementation similar to ``__import__``. Use `follow`
        to actually follow the imports.

        *level* specifies whether to use absolute or relative imports. 0 (the
        default) means only perform absolute imports. Positive values for level
        indicate the number of parent directories to search relative to the
        directory of the module calling ``__import__()`` (see PEP 328 for the
        details).

        :param import_path: List of namespaces (strings or Names).
        """
        debug.speed('import %s' % (import_path, ))
        self._evaluator = evaluator
        self.level = level
        self.module_context = module_context
        try:
            self.file_path = module_context.py__file__()
        except AttributeError:
            # Can be None for certain compiled modules like 'builtins'.
            self.file_path = None

        if level:
            base = module_context.py__package__().split('.')
            if base == [''] or base == ['__main__']:
                base = []
            if level > len(base):
                path = module_context.py__file__()
                if path is not None:
                    import_path = list(import_path)
                    p = path
                    for i in range(level):
                        p = os.path.dirname(p)
                    dir_name = os.path.basename(p)
                    # This is not the proper way to do relative imports. However, since
                    # Jedi cannot be sure about the entry point, we just calculate an
                    # absolute path here.
                    if dir_name:
                        # TODO those sys.modules modifications are getting
                        # really stupid. this is the 3rd time that we're using
                        # this. We should probably refactor.
                        if path.endswith(os.path.sep + 'os.py'):
                            import_path.insert(0, 'os')
                        else:
                            import_path.insert(0, dir_name)
                    else:
                        _add_error(
                            module_context,
                            import_path[-1],
                            message=
                            'Attempted relative import beyond top-level package.'
                        )
                        import_path = []
                # If no path is defined in the module we have no ideas where we
                # are in the file system. Therefore we cannot know what to do.
                # In this case we just let the path there and ignore that it's
                # a relative path. Not sure if that's a good idea.
            else:
                # Here we basically rewrite the level to 0.
                base = tuple(base)
                if level > 1:
                    base = base[:-level + 1]

                import_path = base + tuple(import_path)
        self.import_path = import_path
Exemplo n.º 60
0
    def update(self, old_lines, new_lines):
        '''
        The algorithm works as follows:

        Equal:
            - Assure that the start is a newline, otherwise parse until we get
              one.
            - Copy from parsed_until_line + 1 to max(i2 + 1)
            - Make sure that the indentation is correct (e.g. add DEDENT)
            - Add old and change positions
        Insert:
            - Parse from parsed_until_line + 1 to min(j2 + 1), hopefully not
              much more.

        Returns the new module node.
        '''
        debug.speed('diff parser start')
        # Reset the used names cache so they get regenerated.
        self._module._used_names = None

        self._parser_lines_new = new_lines
        self._added_newline = False
        if new_lines[-1] != '':
            # The Python grammar needs a newline at the end of a file, but for
            # everything else we keep working with new_lines here.
            self._parser_lines_new = list(new_lines)
            self._parser_lines_new[-1] += '\n'
            self._parser_lines_new.append('')
            self._added_newline = True

        self._reset()

        line_length = len(new_lines)
        sm = difflib.SequenceMatcher(None, old_lines, self._parser_lines_new)
        opcodes = sm.get_opcodes()
        debug.speed('diff parser calculated')
        debug.dbg('diff: line_lengths old: %s, new: %s' %
                  (len(old_lines), line_length))

        for operation, i1, i2, j1, j2 in opcodes:
            debug.dbg('diff %s old[%s:%s] new[%s:%s]', operation, i1 + 1, i2,
                      j1 + 1, j2)

            if j2 == line_length + int(self._added_newline):
                # The empty part after the last newline is not relevant.
                j2 -= 1

            if operation == 'equal':
                line_offset = j1 - i1
                self._copy_from_old_parser(line_offset, i2, j2)
            elif operation == 'replace':
                self._parse(until_line=j2)
            elif operation == 'insert':
                self._parse(until_line=j2)
            else:
                assert operation == 'delete'

        # With this action all change will finally be applied and we have a
        # changed module.
        self._nodes_stack.close()

        if self._added_newline:
            _remove_last_newline(self._module)

        # Good for debugging.
        if debug.debug_function:
            self._enabled_debugging(old_lines, new_lines)
        last_pos = self._module.end_pos[0]
        if last_pos != line_length:
            current_lines = splitlines(self._module.get_code(), keepends=True)
            diff = difflib.unified_diff(current_lines, new_lines)
            raise Exception(
                "There's an issue (%s != %s) with the diff parser. Please report:\n%s"
                % (last_pos, line_length, ''.join(diff)))

        debug.speed('diff parser end')
        return self._module