def visit_instance(self, t: Instance) -> str: if t.type is not None: s = t.type.fullname() or t.type.name() or None else: s = 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 == 'builtins': return obj else: delim = '.' if '.' not in obj else ':' return mod + delim + obj
def visit_instance(self, t: Instance) -> str: if t.type is not None: s = t.type.fullname() or t.type.name() or None else: s = 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 == 'builtins': return obj else: delim = '.' if '.' not in obj else ':' return mod + delim + obj
def lookup_target(modules: Dict[str, MypyFile], target: str) -> List[DeferredNode]: """Look up a target by fully-qualified name.""" module, rest = split_target(modules, target) if rest: components = rest.split('.') else: components = [] node = modules[module] # type: Optional[SymbolNode] file = None # type: Optional[MypyFile] active_class = None active_class_name = None for c in components: if isinstance(node, TypeInfo): active_class = node active_class_name = node.name() # TODO: Is it possible for the assertion to fail? if isinstance(node, MypyFile): file = node assert isinstance(node, (MypyFile, TypeInfo)) 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 result = [DeferredNode(file, None, None)] for name, symnode in node.names.items(): node = symnode.node if isinstance(node, FuncDef): result.extend(lookup_target(modules, target + '.' + name)) return result assert isinstance(node, (FuncDef, MypyFile)) return [DeferredNode(node, active_class_name, active_class)]
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 not isinstance(node, FuncDef): raise SuggestionFailure("Object %s is not a function" % key) return (modname, tail, node)
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 not isinstance(node, FuncDef): raise SuggestionFailure("Object %s is not a function" % key) return (modname, tail, node)
def lookup_target( manager: BuildManager, target: str) -> Tuple[List[DeferredNode], 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 active_class_name = None for c in components: if isinstance(node, TypeInfo): active_class = node active_class_name = node.name() if isinstance(node, MypyFile): file = node if (not isinstance(node, (MypyFile, TypeInfo)) or c not in node.names): not_found() # Stale dependency 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 = [DeferredNode(file, None, 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 [DeferredNode(node, active_class_name, active_class)], None
def lookup_target(manager: BuildManager, target: str) -> List[DeferredNode]: """Look up a target by fully-qualified name.""" 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 [] module, rest = items if rest: components = rest.split('.') else: components = [] node = modules[module] # type: Optional[SymbolNode] file = None # type: Optional[MypyFile] active_class = None active_class_name = None for c in components: if isinstance(node, TypeInfo): active_class = node active_class_name = node.name() if isinstance(node, MypyFile): file = node if (not isinstance(node, (MypyFile, TypeInfo)) or c not in node.names): not_found() # Stale dependency return [] 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 [] result = [DeferredNode(file, None, None)] for name, symnode in node.names.items(): node = symnode.node if isinstance(node, FuncDef): result.extend(lookup_target(manager, target + '.' + name)) return result 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 [] 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 [] return [DeferredNode(node, active_class_name, active_class)]