Exemplo n.º 1
0
def find_item_suggestions(
        name, modaliases, schema, *, item_types=None, limit=3,
        collection=None, condition=None):
    from . import modules as s_mod

    if isinstance(name, sn.Name):
        orig_modname = name.module
        short_name = name.name
    else:
        orig_modname = None
        short_name = name

    modname = modaliases.get(orig_modname, orig_modname)

    suggestions = []

    if collection is not None:
        suggestions.extend(collection)
    else:
        if modname:
            module = schema.get_global(s_mod.Module, modname, None)
            if module:
                suggestions.extend(schema.get_objects(modules=[modname]))

        if not orig_modname:
            suggestions.extend(schema.get_objects(modules=['std']))

    if item_types:
        suggestions = list(
            filter(lambda s: isinstance(s, item_types), suggestions))

    if condition is not None:
        suggestions = list(filter(condition, suggestions))

    # Compute Levenshtein distance for each suggestion.
    with_distance = [
        (s, levenshtein.distance(short_name, get_nq_name(schema, s)))
        for s in suggestions
    ]

    # Filter out suggestions that are too dissimilar.
    max_distance = 3
    closest = list(filter(lambda s: s[1] < max_distance, with_distance))

    # Sort by proximity, then by whether the suggestion is contains
    # the source string at the beginning, then by suggestion name.
    closest.sort(
        key=lambda s: (
            s[1],
            not get_nq_name(schema, s[0]).startswith(short_name),
            s[0].get_displayname(schema)
        )
    )

    return [s[0] for s in closest[:limit]]
Exemplo n.º 2
0
def find_item_suggestions(
    name: Optional[str],
    modaliases: Mapping[Optional[str], str],
    schema: s_schema.Schema,
    *,
    item_types: Tuple[so.ObjectMeta, ...] = (),
    limit: int = 3,
    collection: Optional[Iterable[so.Object]] = None,
    condition: Optional[Callable[[so.Object],
                                 bool]] = None) -> List[so.Object]:
    from . import functions as s_func
    from . import modules as s_mod

    if isinstance(name, sn.Name):
        orig_modname: Optional[str] = name.module
        short_name: str = name.name
    else:
        assert name is not None, ("A name must be provided either "
                                  "as string or SchemaName")
        orig_modname = None
        short_name = name

    modname = modaliases.get(orig_modname, orig_modname)

    suggestions: List[so.Object] = []

    if collection is not None:
        suggestions.extend(collection)
    else:
        if modname:
            module = schema.get_global(s_mod.Module, modname, None)
            if module:
                suggestions.extend(
                    schema.get_objects(included_modules=[modname]))

        if not orig_modname:
            suggestions.extend(schema.get_objects(included_modules=['std']))

    filters = []

    if item_types:
        filters.append(lambda s: isinstance(s, item_types))

    if condition is not None:
        filters.append(condition)

    if not item_types:
        # When schema class is not specified, only suggest generic objects.
        filters.append(lambda s: not sn.is_fullname(s.get_name(schema)))
        filters.append(lambda s: not isinstance(s, s_func.CallableObject))

    # Never suggest object fragments.
    filters.append(lambda s: not isinstance(s, so.ObjectFragment))

    filtered_suggestions = filter(lambda s: all(f(s) for f in filters),
                                  suggestions)

    # Compute Levenshtein distance for each suggestion.
    with_distance: List[Tuple[so.Object, int]] = [
        (s, levenshtein.distance(short_name, get_nq_name(schema, s)))
        for s in filtered_suggestions
    ]

    # Filter out suggestions that are too dissimilar.
    max_distance = 3
    closest = list(filter(lambda s: s[1] < max_distance, with_distance))

    # Sort by proximity, then by whether the suggestion is contains
    # the source string at the beginning, then by suggestion name.
    closest.sort(key=lambda s: (s[1], not get_nq_name(schema, s[0]).startswith(
        short_name), s[0].get_displayname(schema)))

    return [s[0] for s in closest[:limit]]