Example #1
0
def filter_names(inference_state, completion_names, stack, like_name, fuzzy,
                 cached_name):
    comp_dct = set()
    if settings.case_insensitive_completion:
        like_name = like_name.lower()
    for name in completion_names:
        string = name.string_name
        if settings.case_insensitive_completion:
            string = string.lower()
        if helpers.match(string, like_name, fuzzy=fuzzy):
            new = classes.Completion(
                inference_state,
                name,
                stack,
                len(like_name),
                is_fuzzy=fuzzy,
                cached_name=cached_name,
            )
            k = (new.name, new.complete)  # key
            if k not in comp_dct:
                comp_dct.add(k)
                tree_name = name.tree_name
                if tree_name is not None:
                    definition = tree_name.get_definition()
                    if definition is not None and definition.type == 'del_stmt':
                        continue
                yield new
Example #2
0
def filter_names(inference_state, completion_names, stack, like_name, fuzzy):
    comp_dct = {}
    if settings.case_insensitive_completion:
        like_name = like_name.lower()
    for name in completion_names:
        string = name.string_name
        if settings.case_insensitive_completion:
            string = string.lower()
        if fuzzy:
            match = helpers.fuzzy_match(string, like_name)
        else:
            match = helpers.start_match(string, like_name)
        if match:
            new = classes.Completion(
                inference_state,
                name,
                stack,
                len(like_name),
                is_fuzzy=fuzzy,
            )
            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
                yield new
Example #3
0
def file_name_completions(inference_state, module_context, start_leaf, string,
                          like_name, call_signatures_callback, code_lines,
                          position):
    # First we want to find out what can actually be changed as a name.
    like_name_length = len(os.path.basename(string) + like_name)

    addition = _get_string_additions(module_context, start_leaf)
    if addition is None:
        return
    string = addition + string

    # Here we use basename again, because if strings are added like
    # `'foo' + 'bar`, it should complete to `foobar/`.
    must_start_with = os.path.basename(string) + like_name
    string = os.path.dirname(string)

    sigs = call_signatures_callback()
    is_in_os_path_join = sigs and all(s.full_name == 'os.path.join'
                                      for s in sigs)
    if is_in_os_path_join:
        to_be_added = _add_os_path_join(module_context, start_leaf,
                                        sigs[0].bracket_start)
        if to_be_added is None:
            is_in_os_path_join = False
        else:
            string = to_be_added + string
    base_path = os.path.join(inference_state.project._path, string)
    try:
        listed = scandir(base_path)
        # OSError: [Errno 36] File name too long: '...'
    except (FileNotFoundError, OSError):
        return
    for entry in listed:
        name = entry.name
        if name.startswith(must_start_with):
            if is_in_os_path_join or not entry.is_dir():
                if start_leaf.type == 'string':
                    quote = get_string_quote(start_leaf)
                else:
                    assert start_leaf.type == 'error_leaf'
                    quote = start_leaf.value
                potential_other_quote = \
                    code_lines[position[0] - 1][position[1]:position[1] + len(quote)]
                # Add a quote if it's not already there.
                if quote != potential_other_quote:
                    name += quote
            else:
                name += os.path.sep

            yield classes.Completion(
                inference_state,
                FileName(inference_state,
                         name[len(must_start_with) - like_name_length:]),
                stack=None,
                like_name_length=like_name_length)
Example #4
0
def complete_file_name(inference_state, module_context, start_leaf, string,
                       like_name, signatures_callback, code_lines, position,
                       fuzzy):
    # First we want to find out what can actually be changed as a name.
    like_name_length = len(os.path.basename(string))

    addition = _get_string_additions(module_context, start_leaf)
    if addition is None:
        return
    string = addition + string

    # Here we use basename again, because if strings are added like
    # `'foo' + 'bar`, it should complete to `foobar/`.
    must_start_with = os.path.basename(string)
    string = os.path.dirname(string)

    sigs = signatures_callback(*position)
    is_in_os_path_join = sigs and all(s.full_name == 'os.path.join'
                                      for s in sigs)
    if is_in_os_path_join:
        to_be_added = _add_os_path_join(module_context, start_leaf,
                                        sigs[0].bracket_start)
        if to_be_added is None:
            is_in_os_path_join = False
        else:
            string = to_be_added + string
    base_path = os.path.join(inference_state.project._path, string)
    try:
        listed = sorted(scandir(base_path), key=lambda e: e.name)
        # OSError: [Errno 36] File name too long: '...'
    except (FileNotFoundError, OSError):
        return
    for entry in listed:
        name = entry.name
        if fuzzy:
            match = fuzzy_match(name, must_start_with)
        else:
            match = start_match(name, must_start_with)
        if match:
            if is_in_os_path_join or not entry.is_dir():
                name += get_quote_ending(start_leaf.value, code_lines,
                                         position)
            else:
                name += os.path.sep

            yield classes.Completion(
                inference_state,
                PathName(inference_state,
                         name[len(must_start_with) - like_name_length:]),
                stack=None,
                like_name_length=like_name_length,
                is_fuzzy=fuzzy,
            )
Example #5
0
def filter_names(evaluator, completion_names, stack, like_name):
    comp_dct = {}
    for name in completion_names:
        if settings.case_insensitive_completion \
                and name.string_name.lower().startswith(like_name.lower()) \
                or name.string_name.startswith(like_name):

            new = classes.Completion(evaluator, name, stack, len(like_name))
            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
                yield new
Example #6
0
def filter_names(inference_state, completion_names, stack, like_name):
    comp_dct = {}
    if settings.case_insensitive_completion:
        like_name = like_name.lower()
    for name in completion_names:
        string = name.string_name
        if settings.case_insensitive_completion:
            string = string.lower()

        if string.startswith(like_name):
            new = classes.Completion(inference_state, name, stack,
                                     len(like_name))
            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
                yield new
def filter_names(evaluator, completion_names, stack, like_name):
    comp_dct = {}
    for name in set(completion_names):
        if settings.case_insensitive_completion \
                and str(name).lower().startswith(like_name.lower()) \
                or str(name).startswith(like_name):

            if isinstance(name.parent, (tree.Function, tree.Class)):
                # TODO I think this is a hack. It should be an
                #   er.Function/er.Class before that.
                name = evaluator.wrap(name.parent).name
            new = classes.Completion(evaluator, name, stack, len(like_name))
            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
                yield new
Example #8
0
def search_in_module(inference_state,
                     module_context,
                     names,
                     wanted_names,
                     wanted_type,
                     complete=False,
                     fuzzy=False,
                     ignore_imports=False,
                     convert=False):
    for s in wanted_names[:-1]:
        new_names = []
        for n in names:
            if s == n.string_name:
                if n.tree_name is not None and n.api_type == 'module' \
                        and ignore_imports:
                    continue
                new_names += complete_trailer(module_context, n.infer())
        debug.dbg('dot lookup on search %s from %s', new_names, names[:10])
        names = new_names

    last_name = wanted_names[-1].lower()
    for n in names:
        string = n.string_name.lower()
        if complete and helpers.match(string, last_name, fuzzy=fuzzy) \
                or not complete and string == last_name:
            if isinstance(n, SubModuleName):
                names = [v.name for v in n.infer()]
            else:
                names = [n]
            if convert:
                names = convert_names(names)
            for n2 in names:
                if complete:
                    def_ = classes.Completion(
                        inference_state,
                        n2,
                        stack=None,
                        like_name_length=len(last_name),
                        is_fuzzy=fuzzy,
                    )
                else:
                    def_ = classes.Name(inference_state, n2)
                if not wanted_type or wanted_type == def_.type:
                    yield def_
Example #9
0
def filter_names(evaluator, completion_names, stack, like_name):
    comp_dct = {}
    if settings.case_insensitive_completion:
        like_name = like_name.lower()
    for name in completion_names:
        string = name.string_name
        if settings.case_insensitive_completion:
            string = string.lower()

        if settings.fuzzy_completion:
            pattern = '.*'.join(like_name) + '.*'
            match = re.match(pattern, string)
        else:
            match = string.startswith(like_name)

        if match:
            new = classes.Completion(evaluator, name, stack, len(like_name))
            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
                yield new
Example #10
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()))
Example #11
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()))