Esempio n. 1
0
    def visit_instance(self, t: Instance) -> str:
        s = t.type.fullname() or t.type.name() or None
        if s is None:
            return '<???>'
        if s in reverse_builtin_aliases:
            s = reverse_builtin_aliases[s]

        mod_obj = split_target(self.graph, s)
        assert mod_obj
        mod, obj = mod_obj

        # If a class is imported into the current module, rewrite the reference
        # to point to the current module. This helps the annotation tool avoid
        # inserting redundant imports when a type has been reexported.
        if self.module:
            parts = obj.split(
                '.')  # need to split the object part if it is a nested class
            tree = self.graph[self.module].tree
            if tree and parts[0] in tree.names:
                mod = self.module

        if (mod, obj) == ('builtins', 'tuple'):
            mod, obj = 'typing', 'Tuple[' + t.args[0].accept(self) + ', ...]'
        elif t.args != []:
            obj += '[{}]'.format(self.list_str(t.args))

        if mod_obj == ('builtins', 'unicode'):
            return 'Text'
        elif mod == 'builtins':
            return obj
        else:
            delim = '.' if '.' not in obj else ':'
            return mod + delim + obj
Esempio n. 2
0
 def load_final_static(self, fullname: str, typ: RType, line: int,
                       error_name: Optional[str] = None) -> Value:
     split_name = split_target(self.graph, fullname)
     assert split_name is not None
     module, name = split_name
     return self.builder.load_static_checked(
         typ, name, module, line=line,
         error_msg='value for final name "{}" was not set'.format(error_name))
Esempio n. 3
0
 def load_final_static(self, fullname: str, typ: RType, line: int,
                       error_name: Optional[str] = None) -> Value:
     if error_name is None:
         error_name = fullname
     ok_block, error_block = BasicBlock(), BasicBlock()
     split_name = split_target(self.graph, fullname)
     assert split_name is not None
     value = self.add(LoadStatic(typ, split_name[1], split_name[0], line=line))
     self.add(Branch(value, error_block, ok_block, Branch.IS_ERROR, rare=True))
     self.activate_block(error_block)
     self.add(RaiseStandardError(RaiseStandardError.VALUE_ERROR,
                                 'value for final name "{}" was not set'.format(error_name),
                                 line))
     self.add(Unreachable())
     self.activate_block(ok_block)
     return value
Esempio n. 4
0
    def find_node(self, key: str) -> Tuple[str, str, FuncDef]:
        """From a target name, return module/target names and the func def."""
        # TODO: Also return OverloadedFuncDef -- currently these are ignored.
        graph = self.fgmanager.graph
        target = split_target(graph, key)
        if not target:
            raise SuggestionFailure("Cannot find module for %s" % (key, ))
        modname, tail = target

        tree = self.ensure_loaded(graph[modname])

        # N.B. This is reimplemented from update's lookup_target
        # basically just to produce better error messages.

        names = tree.names  # type: SymbolTable

        # Look through any classes
        components = tail.split('.')
        for i, component in enumerate(components[:-1]):
            if component not in names:
                raise SuggestionFailure(
                    "Unknown class %s.%s" %
                    (modname, '.'.join(components[:i + 1])))
            node = names[component].node  # type: Optional[SymbolNode]
            if not isinstance(node, TypeInfo):
                raise SuggestionFailure(
                    "Object %s.%s is not a class" %
                    (modname, '.'.join(components[:i + 1])))
            names = node.names

        # Look for the actual function/method
        funcname = components[-1]
        if funcname not in names:
            raise SuggestionFailure(
                "Unknown %s %s" %
                ("method" if len(components) > 1 else "function", key))
        node = names[funcname].node
        if isinstance(node, Decorator):
            node = self.extract_from_decorator(node)
            if not node:
                raise SuggestionFailure(
                    "Object %s is a decorator we can't handle" % key)

        if not isinstance(node, FuncDef):
            raise SuggestionFailure("Object %s is not a function" % key)

        return (modname, tail, node)
Esempio n. 5
0
    def find_node(self, key: str) -> Tuple[str, str, FuncDef]:
        """From a target name, return module/target names and the func def.

        The 'key' argument can be in one of two formats:
        * As the function full name, e.g., package.module.Cls.method
        * As the function location as file and line separated by column,
          e.g., path/to/file.py:42
        """
        # TODO: Also return OverloadedFuncDef -- currently these are ignored.
        node = None  # type: Optional[SymbolNode]
        if ':' in key:
            if key.count(':') > 1:
                raise SuggestionFailure(
                    'Malformed location for function: {}. Must be either'
                    ' package.module.Class.method or path/to/file.py:line'.
                    format(key))
            file, line = key.split(':')
            if not line.isdigit():
                raise SuggestionFailure(
                    'Line number must be a number. Got {}'.format(line))
            line_number = int(line)
            modname, node = self.find_node_by_file_and_line(file, line_number)
            tail = node.fullname()[len(modname) +
                                   1:]  # add one to account for '.'
        else:
            target = split_target(self.fgmanager.graph, key)
            if not target:
                raise SuggestionFailure("Cannot find module for %s" % (key, ))
            modname, tail = target
            node = self.find_node_by_module_and_name(modname, tail)

        if isinstance(node, Decorator):
            node = self.extract_from_decorator(node)
            if not node:
                raise SuggestionFailure(
                    "Object %s is a decorator we can't handle" % key)

        if not isinstance(node, FuncDef):
            raise SuggestionFailure("Object %s is not a function" % key)

        return modname, tail, node
Esempio n. 6
0
def lookup_target(manager: BuildManager,
                  target: str) -> Tuple[List[FineGrainedDeferredNode], Optional[TypeInfo]]:
    """Look up a target by fully-qualified name.

    The first item in the return tuple is a list of deferred nodes that
    needs to be reprocessed. If the target represents a TypeInfo corresponding
    to a protocol, return it as a second item in the return tuple, otherwise None.
    """
    def not_found() -> None:
        manager.log_fine_grained(
            "Can't find matching target for %s (stale dependency?)" % target)

    modules = manager.modules
    items = split_target(modules, target)
    if items is None:
        not_found()  # Stale dependency
        return [], None
    module, rest = items
    if rest:
        components = rest.split('.')
    else:
        components = []
    node = modules[module]  # type: Optional[SymbolNode]
    file = None  # type: Optional[MypyFile]
    active_class = None
    for c in components:
        if isinstance(node, TypeInfo):
            active_class = node
        if isinstance(node, MypyFile):
            file = node
        if (not isinstance(node, (MypyFile, TypeInfo))
                or c not in node.names):
            not_found()  # Stale dependency
            return [], None
        # Don't reprocess plugin generated targets. They should get
        # stripped and regenerated when the containing target is
        # reprocessed.
        if node.names[c].plugin_generated:
            return [], None
        node = node.names[c].node
    if isinstance(node, TypeInfo):
        # A ClassDef target covers the body of the class and everything defined
        # within it.  To get the body we include the entire surrounding target,
        # typically a module top-level, since we don't support processing class
        # bodies as separate entitites for simplicity.
        assert file is not None
        if node.fullname != target:
            # This is a reference to a different TypeInfo, likely due to a stale dependency.
            # Processing them would spell trouble -- for example, we could be refreshing
            # a deserialized TypeInfo with missing attributes.
            not_found()
            return [], None
        result = [FineGrainedDeferredNode(file, None)]
        stale_info = None  # type: Optional[TypeInfo]
        if node.is_protocol:
            stale_info = node
        for name, symnode in node.names.items():
            node = symnode.node
            if isinstance(node, FuncDef):
                method, _ = lookup_target(manager, target + '.' + name)
                result.extend(method)
        return result, stale_info
    if isinstance(node, Decorator):
        # Decorator targets actually refer to the function definition only.
        node = node.func
    if not isinstance(node, (FuncDef,
                             MypyFile,
                             OverloadedFuncDef)):
        # The target can't be refreshed. It's possible that the target was
        # changed to another type and we have a stale dependency pointing to it.
        not_found()
        return [], None
    if node.fullname != target:
        # Stale reference points to something unexpected. We shouldn't process since the
        # context will be wrong and it could be a partially initialized deserialized node.
        not_found()
        return [], None
    return [FineGrainedDeferredNode(node, active_class)], None