def visit_symbol_table(self, symtab: SymbolTable, table_fullname: str) -> None: # Copy the items because we may mutate symtab. for key, value in list(symtab.items()): cross_ref = value.cross_ref if cross_ref is not None: # Fix up cross-reference. value.cross_ref = None if cross_ref in self.modules: value.node = self.modules[cross_ref] else: stnode = lookup_fully_qualified( cross_ref, self.modules, raise_on_missing=not self.allow_missing) if stnode is not None: assert stnode.node is not None, (table_fullname + "." + key, cross_ref) value.node = stnode.node elif not self.allow_missing: assert False, "Could not find cross-ref %s" % ( cross_ref, ) else: # We have a missing crossref in allow missing mode, need to put something value.node = missing_info(self.modules) else: if isinstance(value.node, TypeInfo): # TypeInfo has no accept(). TODO: Add it? self.visit_type_info(value.node) elif value.node is not None: value.node.accept(self) else: assert False, 'Unexpected empty node %r: %s' % (key, value)
def visit_typeddict_type(self, tdt: TypedDictType) -> None: if tdt.items: for it in tdt.items.values(): it.accept(self) if tdt.fallback is not None: if tdt.fallback.type_ref is not None: if lookup_fully_qualified(tdt.fallback.type_ref, self.modules, raise_on_missing=not self.allow_missing) is None: # We reject fake TypeInfos for TypedDict fallbacks because # the latter are used in type checking and must be valid. tdt.fallback.type_ref = 'typing._TypedDict' tdt.fallback.accept(self)
def lookup_fully_qualified_alias(modules: Dict[str, MypyFile], name: str, *, allow_missing: bool) -> TypeAlias: stnode = lookup_fully_qualified(name, modules, raise_on_missing=not allow_missing) node = stnode.node if stnode else None if isinstance(node, TypeAlias): return node else: # Looks like a missing TypeAlias during an initial daemon load, put something there assert allow_missing, "Should never get here in normal mode," \ " got {}:{} instead of TypeAlias".format(type(node).__name__, node.fullname if node else '') return missing_alias()
def argument(self, ctx: 'mypy.plugin.ClassDefContext') -> Argument: """Return this attribute as an argument to __init__.""" assert self.init init_type = self.init_type or self.info[self.name].type if self.converter.name: # When a converter is set the init_type is overridden by the first argument # of the converter method. converter = lookup_fully_qualified(self.converter.name, ctx.api.modules, raise_on_missing=False) if not converter: # The converter may be a local variable. Check there too. converter = ctx.api.lookup_qualified(self.converter.name, self.info, True) # Get the type of the converter. converter_type: Optional[Type] = None if converter and isinstance(converter.node, TypeInfo): from mypy.checkmember import type_object_type # To avoid import cycle. converter_type = type_object_type(converter.node, ctx.api.named_type) elif converter and isinstance(converter.node, OverloadedFuncDef): converter_type = converter.node.type elif converter and converter.type: converter_type = converter.type init_type = None converter_type = get_proper_type(converter_type) if isinstance(converter_type, CallableType) and converter_type.arg_types: init_type = ctx.api.anal_type(converter_type.arg_types[0]) elif isinstance(converter_type, Overloaded): types: List[Type] = [] for item in converter_type.items: # Walk the overloads looking for methods that can accept one argument. num_arg_types = len(item.arg_types) if not num_arg_types: continue if num_arg_types > 1 and any( kind == ARG_POS for kind in item.arg_kinds[1:]): continue types.append(item.arg_types[0]) # Make a union of all the valid types. if types: args = make_simplified_union(types) init_type = ctx.api.anal_type(args) if self.converter.is_attr_converters_optional and init_type: # If the converter was attr.converter.optional(type) then add None to # the allowed init_type. init_type = UnionType.make_union([init_type, NoneType()]) if not init_type: ctx.api.fail("Cannot determine __init__ type from converter", self.context) init_type = AnyType(TypeOfAny.from_error) elif self.converter.name == '': # This means we had a converter but it's not of a type we can infer. # Error was shown in _get_converter_name init_type = AnyType(TypeOfAny.from_error) if init_type is None: if ctx.api.options.disallow_untyped_defs: # This is a compromise. If you don't have a type here then the # __init__ will be untyped. But since the __init__ is added it's # pointing at the decorator. So instead we also show the error in the # assignment, which is where you would fix the issue. node = self.info[self.name].node assert node is not None ctx.api.msg.need_annotation_for_var(node, self.context) # Convert type not set to Any. init_type = AnyType(TypeOfAny.unannotated) if self.kw_only: arg_kind = ARG_NAMED_OPT if self.has_default else ARG_NAMED else: arg_kind = ARG_OPT if self.has_default else ARG_POS # Attrs removes leading underscores when creating the __init__ arguments. return Argument(Var(self.name.lstrip("_"), init_type), init_type, None, arg_kind)
def lookup_fully_qualified(self, fullname: str) -> Optional[SymbolTableNode]: assert self._modules is not None return lookup_fully_qualified(fullname, self._modules)
def lookup_qualified_stnode(modules: Dict[str, MypyFile], name: str, allow_missing: bool) -> Optional[SymbolTableNode]: return lookup_fully_qualified(name, modules, raise_on_missing=not allow_missing)
def lookup_qualified_stnode(modules: Dict[str, MypyFile], name: str, quick_and_dirty: bool) -> Optional[SymbolTableNode]: return lookup_fully_qualified(name, modules, raise_on_missing=not quick_and_dirty)