def add_new_class_for_module(module: MypyFile, name: str, bases: List[Instance], fields: 'OrderedDict[str, MypyType]') -> TypeInfo: new_class_unique_name = checker.gen_unique_name(name, module.names) # make new class expression classdef = ClassDef(new_class_unique_name, Block([])) classdef.fullname = module.fullname() + '.' + new_class_unique_name # make new TypeInfo new_typeinfo = TypeInfo(SymbolTable(), classdef, module.fullname()) new_typeinfo.bases = bases calculate_mro(new_typeinfo) new_typeinfo.calculate_metaclass_type() def add_field_to_new_typeinfo(var: Var, is_initialized_in_class: bool = False, is_property: bool = False) -> None: var.info = new_typeinfo var.is_initialized_in_class = is_initialized_in_class var.is_property = is_property var._fullname = new_typeinfo.fullname() + '.' + var.name() new_typeinfo.names[var.name()] = SymbolTableNode(MDEF, var) # add fields var_items = [Var(item, typ) for item, typ in fields.items()] for var_item in var_items: add_field_to_new_typeinfo(var_item, is_property=True) classdef.info = new_typeinfo module.names[new_class_unique_name] = SymbolTableNode( GDEF, new_typeinfo, plugin_generated=True) return new_typeinfo
def _dynamic_class_hook(ctx: DynamicClassDefContext) -> None: """Generate a declarative Base class when the declarative_base() function is encountered.""" _add_globals(ctx) cls = ClassDef(ctx.name, Block([])) cls.fullname = ctx.api.qualified_name(ctx.name) info = TypeInfo(SymbolTable(), cls, ctx.api.cur_mod_id) cls.info = info _set_declarative_metaclass(ctx.api, cls) cls_arg = util.get_callexpr_kwarg(ctx.call, "cls", expr_types=(NameExpr, )) if cls_arg is not None and isinstance(cls_arg.node, TypeInfo): util.set_is_base(cls_arg.node) decl_class.scan_declarative_assignments_and_apply_types( cls_arg.node.defn, ctx.api, is_mixin_scan=True) info.bases = [Instance(cls_arg.node, [])] else: obj = ctx.api.named_type(names.NAMED_TYPE_BUILTINS_OBJECT) info.bases = [obj] try: calculate_mro(info) except MroError: util.fail(ctx.api, "Not able to calculate MRO for declarative base", ctx.call) obj = ctx.api.named_type(names.NAMED_TYPE_BUILTINS_OBJECT) info.bases = [obj] info.fallback_to_any = True ctx.api.add_symbol_table_node(ctx.name, SymbolTableNode(GDEF, info)) util.set_is_base(info)
def analyze_namedtuple_classdef(self, defn: ClassDef, is_stub_file: bool ) -> Tuple[bool, Optional[TypeInfo]]: """Analyze if given class definition can be a named tuple definition. Return a tuple where first item indicates whether this can possibly be a named tuple, and the second item is the corresponding TypeInfo (may be None if not ready and should be deferred). """ for base_expr in defn.base_type_exprs: if isinstance(base_expr, RefExpr): self.api.accept(base_expr) if base_expr.fullname == 'typing.NamedTuple': result = self.check_namedtuple_classdef(defn, is_stub_file) if result is None: # This is a valid named tuple, but some types are incomplete. return True, None items, types, default_items = result info = self.build_namedtuple_typeinfo( defn.name, items, types, default_items, defn.line) defn.info = info defn.analyzed = NamedTupleExpr(info, is_typed=True) defn.analyzed.line = defn.line defn.analyzed.column = defn.column # All done: this is a valid named tuple with all types known. return True, info # This can't be a valid named tuple. return False, None
def make_type_info(self, name: str, is_abstract: bool = False, mro: List[TypeInfo] = None, bases: List[Instance] = None, typevars: List[str] = None) -> TypeInfo: """Make a TypeInfo suitable for use in unit tests.""" class_def = ClassDef(name, Block([]), None, []) class_def.fullname = name if typevars: v = [] # type: List[TypeVarDef] id = 1 for n in typevars: v.append(TypeVarDef(n, id, None, self.oi)) id += 1 class_def.type_vars = v info = TypeInfo(SymbolTable(), class_def) if mro is None: mro = [] if name != 'builtins.object': mro.append(self.oi) info.mro = [info] + mro if bases is None: if mro: # By default, assume that there is a single non-generic base. bases = [Instance(mro[0], [])] else: bases = [] info.bases = bases return info
def make_type_info(name: str, is_abstract: bool = False, mro: List[TypeInfo] = None, bases: List[Instance] = None, typevars: List[str] = None) -> TypeInfo: """Make a TypeInfo suitable for use in unit tests.""" class_def = ClassDef(name, Block([]), None, []) class_def.fullname = name if typevars: v = [] # type: List[TypeVarDef] id = 1 for n in typevars: v.append(TypeVarDef(n, id, None)) id += 1 class_def.type_vars = v info = TypeInfo(SymbolTable(), class_def) if mro is None: mro = [] info.mro = [info] + mro if bases is None: if mro: # By default, assume that there is a single non-generic base. bases = [Instance(mro[0], [])] else: bases = [] info.bases = bases return info
def add_new_class_for_module(module: MypyFile, name: str, bases: List[Instance], fields: Optional[Dict[str, MypyType]] = None ) -> TypeInfo: new_class_unique_name = checker.gen_unique_name(name, module.names) # make new class expression classdef = ClassDef(new_class_unique_name, Block([])) classdef.fullname = module.fullname + '.' + new_class_unique_name # make new TypeInfo new_typeinfo = TypeInfo(SymbolTable(), classdef, module.fullname) new_typeinfo.bases = bases calculate_mro(new_typeinfo) new_typeinfo.calculate_metaclass_type() # add fields if fields: for field_name, field_type in fields.items(): var = Var(field_name, type=field_type) var.info = new_typeinfo var._fullname = new_typeinfo.fullname + '.' + field_name new_typeinfo.names[field_name] = SymbolTableNode(MDEF, var, plugin_generated=True) classdef.info = new_typeinfo module.names[new_class_unique_name] = SymbolTableNode(GDEF, new_typeinfo, plugin_generated=True) return new_typeinfo
def analyze_namedtuple_classdef(self, defn: ClassDef) -> Tuple[bool, Optional[TypeInfo]]: """Analyze if given class definition can be a named tuple definition. Return a tuple where first item indicates whether this can possibly be a named tuple, and the second item is the corresponding TypeInfo (may be None if not ready and should be deferred). """ for base_expr in defn.base_type_exprs: if isinstance(base_expr, RefExpr): self.api.accept(base_expr) if base_expr.fullname == 'typing.NamedTuple': result = self.check_namedtuple_classdef(defn) if result is None: # This is a valid named tuple, but some types are incomplete. return True, None items, types, default_items = result info = self.build_namedtuple_typeinfo( defn.name, items, types, default_items, defn.line) defn.info = info defn.analyzed = NamedTupleExpr(info, is_typed=True) defn.analyzed.line = defn.line defn.analyzed.column = defn.column # All done: this is a valid named tuple with all types known. return True, info # This can't be a valid named tuple. return False, None
def _combine_protocols(p1: Instance, p2: Instance) -> Instance: def base_repr(base): if 'pfun.Intersection' in base.type.fullname: return ', '.join([repr(b) for b in base.type.bases]) return repr(base) def get_bases(base): if 'pfun.Intersection' in base.type.fullname: bases = set() for b in base.type.bases: bases |= get_bases(b) return bases return set([base]) names = p1.type.names.copy() names.update(p2.type.names) keywords = p1.type.defn.keywords.copy() keywords.update(p2.type.defn.keywords) bases = get_bases(p1) | get_bases(p2) bases_repr = ', '.join(sorted([repr(base) for base in bases])) name = f'Intersection[{bases_repr}]' defn = ClassDef(name, Block([]), p1.type.defn.type_vars + p2.type.defn.type_vars, [NameExpr(p1.type.fullname), NameExpr(p2.type.fullname)], None, list(keywords.items())) defn.fullname = f'pfun.{name}' info = TypeInfo(names, defn, '') info.is_protocol = True info.is_abstract = True info.bases = [p1, p2] info.abstract_attributes = (p1.type.abstract_attributes + p2.type.abstract_attributes) calculate_mro(info) return Instance(info, p1.args + p2.args)
def visit_class_def(self, node: ClassDef) -> None: """Strip class body and type info, but don't strip methods.""" self.strip_type_info(node.info) node.type_vars = [] node.base_type_exprs.extend(node.removed_base_type_exprs) node.removed_base_type_exprs = [] with self.enter_class(node.info): super().visit_class_def(node)
def transform_class_def(self, tdef: ClassDef) -> List[Node]: """Transform a type definition. The result may be one or two definitions. The first is the transformation of the original ClassDef. The second is a wrapper type, which is generated for generic types only. """ defs = [] # type: List[Node] if tdef.info.type_vars: # This is a generic type. Insert type variable slots in # the class definition for new type variables, i.e. type # variables not mapped to superclass type variables. defs.extend(self.make_tvar_representation(tdef.info)) # Iterate over definitions and transform each of them. vars = set() # type: Set[Var] for d in tdef.defs.body: if isinstance(d, FuncDef): # Implicit cast from FuncDef[] to Node[] is safe below. defs.extend(Any(self.func_tf.transform_method(d))) elif isinstance(d, VarDef): defs.extend(self.transform_var_def(d)) for n in d.items: vars.add(n) elif isinstance(d, AssignmentStmt): self.transform_assignment(d) defs.append(d) # Add accessors for implicitly defined attributes. for node in tdef.info.names.values(): if isinstance(node.node, Var): v = cast(Var, node.node) if v.info == tdef.info and v not in vars: defs.extend(self.make_accessors(v)) # For generic classes, add an implicit __init__ wrapper. defs.extend(self.make_init_wrapper(tdef)) if tdef.is_generic() or (tdef.info.bases and tdef.info.mro[1].is_generic()): self.make_instance_tvar_initializer( cast(FuncDef, tdef.info.get_method('__init__'))) if not defs: defs.append(PassStmt()) if tdef.is_generic(): gen_wrapper = self.generic_class_wrapper(tdef) tdef.defs = Block(defs) dyn_wrapper = self.make_type_object_wrapper(tdef) if not tdef.is_generic(): return [tdef, dyn_wrapper] else: return [tdef, dyn_wrapper, gen_wrapper]
def _create_intersection(args, context, api): defn = ClassDef('Intersection', Block([])) defn.fullname = 'pfun.Intersection' info = TypeInfo({}, defn, 'pfun') info.is_protocol = True calculate_mro(info) i = Instance(info, args, line=context.line, column=context.column) intersection_translator = TranslateIntersection(api, i) return i.accept(intersection_translator)
def stale_info() -> TypeInfo: suggestion = "<stale cache: consider running mypy without --quick>" dummy_def = ClassDef(suggestion, Block([])) dummy_def.fullname = suggestion info = TypeInfo(SymbolTable(), dummy_def, "<stale>") info.mro = [info] info.bases = [] return info
def visit_class_def(self, node: ClassDef) -> ClassDef: new = ClassDef(node.name, self.block(node.defs), node.type_vars, self.expressions(node.base_type_exprs), node.metaclass) new.fullname = node.fullname new.info = node.info new.decorators = [ self.expr(decorator) for decorator in node.decorators ] return new
def missing_info(modules: Dict[str, MypyFile]) -> TypeInfo: suggestion = _SUGGESTION.format('info') dummy_def = ClassDef(suggestion, Block([])) dummy_def.fullname = suggestion info = TypeInfo(SymbolTable(), dummy_def, "<missing>") obj_type = lookup_fully_qualified_typeinfo(modules, 'builtins.object', allow_missing=False) info.bases = [Instance(obj_type, [])] info.mro = [info, obj_type] return info
def visit_class_def(self, node: ClassDef) -> None: """Strip class body and type info, but don't strip methods.""" to_delete = set(self.strip_type_info(node.info)) node.type_vars = [] node.base_type_exprs.extend(node.removed_base_type_exprs) node.removed_base_type_exprs = [] node.defs.body = [s for s in node.defs.body if s not in to_delete] with self.enter_class(node.info): super().visit_class_def(node)
def visit_class_def(self, node: ClassDef) -> Node: new = ClassDef(node.name, self.block(node.defs), node.type_vars, self.nodes(node.base_type_exprs), node.metaclass) new.fullname = node.fullname new.info = node.info new.decorators = [ decorator.accept(self) for decorator in node.decorators ] new.is_builtinclass = node.is_builtinclass return new
def missing_info(modules: Dict[str, MypyFile]) -> TypeInfo: suggestion = "<missing info: *should* have gone away during fine-grained update>" dummy_def = ClassDef(suggestion, Block([])) dummy_def.fullname = suggestion info = TypeInfo(SymbolTable(), dummy_def, "<missing>") obj_type = lookup_qualified(modules, 'builtins.object', False) assert isinstance(obj_type, TypeInfo) info.bases = [Instance(obj_type, [])] info.mro = [info, obj_type] return info
def add_info_hook(ctx) -> None: class_def = ClassDef(ctx.name, Block([])) class_def.fullname = ctx.api.qualified_name(ctx.name) info = TypeInfo(SymbolTable(), class_def, ctx.api.cur_mod_id) class_def.info = info obj = ctx.api.builtin_type('builtins.object') info.mro = [info, obj.type] info.bases = [obj] ctx.api.add_symbol_table_node(ctx.name, SymbolTableNode(GDEF, info)) info.metadata['magic'] = True
def visit_ClassDef(self, n: ast27.ClassDef) -> ClassDef: self.class_nesting += 1 cdef = ClassDef(n.name, self.as_required_block(n.body, n.lineno), None, self.translate_expr_list(n.bases), metaclass=None) cdef.decorators = self.translate_expr_list(n.decorator_list) self.class_nesting -= 1 return cdef
def add_info_hook(ctx) -> None: class_def = ClassDef(ctx.name, Block([])) class_def.fullname = ctx.api.qualified_name(ctx.name) info = TypeInfo(SymbolTable(), class_def, ctx.api.cur_mod_id) class_def.info = info obj = ctx.api.named_type('builtins.object') info.mro = [info, obj.type] info.bases = [obj] ctx.api.add_symbol_table_node(ctx.name, SymbolTableNode(GDEF, info)) info.metadata['magic'] = True
def visit_ClassDef(self, n: ast27.ClassDef) -> ClassDef: self.class_nesting += 1 cdef = ClassDef(n.name, self.as_block(n.body, n.lineno), None, self.translate_expr_list(n.bases), metaclass=None) cdef.decorators = self.translate_expr_list(n.decorator_list) self.class_nesting -= 1 return cdef
def visit_ClassDef(self, n: ast27.ClassDef) -> Node: self.class_nesting += 1 cdef = ClassDef(n.name, self.as_block(n.body, n.lineno), None, self.visit_list(n.bases), metaclass=None) cdef.decorators = self.visit_list(n.decorator_list) self.class_nesting -= 1 return cdef
def visit_class_def(self, node: ClassDef) -> ClassDef: new = ClassDef(node.name, self.block(node.defs), node.type_vars, self.expressions(node.base_type_exprs), node.metaclass) new.fullname = node.fullname new.info = node.info new.decorators = [self.expr(decorator) for decorator in node.decorators] return new
def add_info_hook(ctx): class_def = ClassDef(ctx.name, Block([])) class_def.fullname = ctx.api.qualified_name(ctx.name) info = TypeInfo(SymbolTable(), class_def, ctx.api.cur_mod_id) class_def.info = info obj = ctx.api.builtin_type('builtins.object') info.mro = [info, obj.type] info.bases = [obj] ctx.api.add_symbol_table_node(ctx.name, SymbolTableNode(GDEF, info)) DECL_BASES.add(class_def.fullname)
def stale_info(modules: Dict[str, MypyFile]) -> TypeInfo: suggestion = "<stale cache: consider running mypy without --quick>" dummy_def = ClassDef(suggestion, Block([])) dummy_def.fullname = suggestion info = TypeInfo(SymbolTable(), dummy_def, "<stale>") obj_type = lookup_qualified(modules, 'builtins.object', False) assert isinstance(obj_type, TypeInfo) info.bases = [Instance(obj_type, [])] info.mro = [info, obj_type] return info
def visit_ClassDef(self, n: ast27.ClassDef) -> ClassDef: self.class_and_function_stack.append('C') cdef = ClassDef(n.name, self.as_required_block(n.body, n.lineno), None, self.translate_expr_list(n.bases), metaclass=None) cdef.decorators = self.translate_expr_list(n.decorator_list) self.set_line(cdef, n) self.class_and_function_stack.pop() return cdef
def add_info_hook(ctx: DynamicClassDefContext): class_def = ClassDef(ctx.name, Block([])) class_def.fullname = ctx.api.qualified_name(ctx.name) info = TypeInfo(SymbolTable(), class_def, ctx.api.cur_mod_id) class_def.info = info queryset_type_fullname = ctx.call.args[0].fullname queryset_info = ctx.api.lookup_fully_qualified_or_none(queryset_type_fullname).node # type: TypeInfo obj = ctx.api.named_type('builtins.object') info.mro = [info, queryset_info, obj.type] info.bases = [Instance(queryset_info, [])] ctx.api.add_symbol_table_node(ctx.name, SymbolTableNode(GDEF, info))
def visit_class_def(self, cdef: ClassDef) -> None: kind = self.kind_by_scope() if kind == LDEF: return elif kind == GDEF: self.sem.check_no_global(cdef.name, cdef) cdef.fullname = self.sem.qualified_name(cdef.name) info = TypeInfo(SymbolTable(), cdef, self.sem.cur_mod_id) info.set_line(cdef.line, cdef.column) cdef.info = info if kind == GDEF: self.sem.globals[cdef.name] = SymbolTableNode(kind, info) self.process_nested_classes(cdef)
def visit_ClassDef(self, n: ast3.ClassDef) -> ClassDef: self.class_nesting += 1 keywords = [(kw.arg, self.visit(kw.value)) for kw in n.keywords if kw.arg] cdef = ClassDef(n.name, self.as_required_block(n.body, n.lineno), None, self.translate_expr_list(n.bases), metaclass=dict(keywords).get('metaclass'), keywords=keywords) cdef.decorators = self.translate_expr_list(n.decorator_list) self.class_nesting -= 1 return cdef
def visit_ClassDef(self, n: ast27.ClassDef) -> ClassDef: self.class_and_function_stack.append('C') cdef = ClassDef(n.name, self.as_required_block(n.body, n.lineno), None, self.translate_expr_list(n.bases), metaclass=None) cdef.decorators = self.translate_expr_list(n.decorator_list) cdef.line = n.lineno + len(n.decorator_list) cdef.column = n.col_offset cdef.end_line = n.lineno self.class_and_function_stack.pop() return cdef
def make_fake_register_class_instance(api: CheckerPluginInterface, type_args: Sequence[Type] ) -> Instance: defn = ClassDef(REGISTER_RETURN_CLASS, Block([])) defn.fullname = f'functools.{REGISTER_RETURN_CLASS}' info = TypeInfo(SymbolTable(), defn, "functools") obj_type = api.named_generic_type('builtins.object', []).type info.bases = [Instance(obj_type, [])] info.mro = [info, obj_type] defn.info = info func_arg = Argument(Var('name'), AnyType(TypeOfAny.implementation_artifact), None, ARG_POS) add_method_to_class(api, defn, '__call__', [func_arg], NoneType()) return Instance(info, type_args)
def visit_ClassDef(self, n: ast35.ClassDef) -> ClassDef: self.class_nesting += 1 metaclass_arg = find(lambda x: x.arg == 'metaclass', n.keywords) metaclass = None if metaclass_arg: metaclass = self.stringify_name(metaclass_arg.value) cdef = ClassDef(n.name, self.as_block(n.body, n.lineno), None, self.translate_expr_list(n.bases), metaclass=metaclass) cdef.decorators = self.translate_expr_list(n.decorator_list) self.class_nesting -= 1 return cdef
def visit_ClassDef(self, n): self.in_class = True metaclass_arg = find(lambda x: x.arg == 'metaclass', n.keywords) metaclass = None if metaclass_arg: metaclass = self.stringify_name(metaclass_arg.value) cdef = ClassDef(n.name, Block(self.fix_function_overloads(self.visit(n.body))), None, self.visit(n.bases), metaclass=metaclass) cdef.decorators = self.visit(n.decorator_list) self.in_class = False return cdef
def visit_ClassDef(self, n: ast35.ClassDef) -> Node: self.class_nesting += 1 metaclass_arg = find(lambda x: x.arg == 'metaclass', n.keywords) metaclass = None if metaclass_arg: metaclass = self.stringify_name(metaclass_arg.value) cdef = ClassDef(n.name, Block(self.fix_function_overloads(self.visit_list(n.body))), None, self.visit_list(n.bases), metaclass=metaclass) cdef.decorators = self.visit_list(n.decorator_list) self.class_nesting -= 1 return cdef
def decl_info_hook(ctx: DynamicClassDefContext) -> None: """Support dynamically defining declarative bases. For example: from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() """ cls_bases = [] # type: List[Instance] # Passing base classes as positional arguments is currently not handled. if 'cls' in ctx.call.arg_names: declarative_base_cls_arg = ctx.call.args[ctx.call.arg_names.index( "cls")] if isinstance(declarative_base_cls_arg, TupleExpr): items = [item for item in declarative_base_cls_arg.items] else: items = [declarative_base_cls_arg] for item in items: if isinstance(item, RefExpr) and isinstance(item.node, TypeInfo): base = fill_typevars_with_any(item.node) # TODO: Support tuple types? if isinstance(base, Instance): cls_bases.append(base) class_def = ClassDef(ctx.name, Block([])) class_def.fullname = ctx.api.qualified_name(ctx.name) info = TypeInfo(SymbolTable(), class_def, ctx.api.cur_mod_id) class_def.info = info obj = ctx.api.builtin_type('builtins.object') info.bases = cls_bases or [obj] try: calculate_mro(info) except MroError: ctx.api.fail("Not able to calculate MRO for declarative base", ctx.call) info.bases = [obj] info.fallback_to_any = True ctx.api.add_symbol_table_node(ctx.name, SymbolTableNode(GDEF, info)) set_declarative(info) # TODO: check what else is added. add_metadata_var(ctx.api, info)
def visit_class_def(self, node: ClassDef) -> None: # TODO additional things? node.defs.body = self.replace_statements(node.defs.body) node.info = self.fixup(node.info) for tv in node.type_vars: self.process_type_var_def(tv) self.process_type_info(node.info) super().visit_class_def(node)
def visit_ClassDef(self, n: ast35.ClassDef) -> ClassDef: self.class_nesting += 1 metaclass_arg = find(lambda x: x.arg == 'metaclass', n.keywords) metaclass = None if metaclass_arg: metaclass = self.stringify_name(metaclass_arg.value) if metaclass is None: metaclass = '<error>' # To be reported later cdef = ClassDef(n.name, self.as_block(n.body, n.lineno), None, self.translate_expr_list(n.bases), metaclass=metaclass) cdef.decorators = self.translate_expr_list(n.decorator_list) self.class_nesting -= 1 return cdef
def make_type_info(self, name: str, module_name: Optional[str] = None, is_abstract: bool = False, mro: Optional[List[TypeInfo]] = None, bases: Optional[List[Instance]] = None, typevars: Optional[List[str]] = None, variances: Optional[List[int]] = None) -> TypeInfo: """Make a TypeInfo suitable for use in unit tests.""" class_def = ClassDef(name, Block([]), None, []) class_def.fullname = name if module_name is None: if '.' in name: module_name = name.rsplit('.', 1)[0] else: module_name = '__main__' if typevars: v: List[TypeVarLikeType] = [] for id, n in enumerate(typevars, 1): if variances: variance = variances[id - 1] else: variance = COVARIANT v.append(TypeVarType(n, n, id, [], self.o, variance=variance)) class_def.type_vars = v info = TypeInfo(SymbolTable(), class_def, module_name) if mro is None: mro = [] if name != 'builtins.object': mro.append(self.oi) info.mro = [info] + mro if bases is None: if mro: # By default, assume that there is a single non-generic base. bases = [Instance(mro[0], [])] else: bases = [] info.bases = bases return info
def make_type_info(self, name: str, module_name: Optional[str] = None, is_abstract: bool = False, mro: Optional[List[TypeInfo]] = None, bases: Optional[List[Instance]] = None, typevars: Optional[List[str]] = None, variances: Optional[List[int]] = None) -> TypeInfo: """Make a TypeInfo suitable for use in unit tests.""" class_def = ClassDef(name, Block([]), None, []) class_def.fullname = name if module_name is None: if '.' in name: module_name = name.rsplit('.', 1)[0] else: module_name = '__main__' if typevars: v = [] # type: List[TypeVarDef] for id, n in enumerate(typevars, 1): if variances: variance = variances[id - 1] else: variance = COVARIANT v.append(TypeVarDef(n, n, id, [], self.o, variance=variance)) class_def.type_vars = v info = TypeInfo(SymbolTable(), class_def, module_name) if mro is None: mro = [] if name != 'builtins.object': mro.append(self.oi) info.mro = [info] + mro if bases is None: if mro: # By default, assume that there is a single non-generic base. bases = [Instance(mro[0], [])] else: bases = [] info.bases = bases return info
def visit_class_def(self, node: ClassDef) -> None: """Strip class body and type info, but don't strip methods.""" node.info.type_vars = [] node.info.bases = [] node.info.abstract_attributes = [] node.info.mro = [] node.info.add_type_vars() node.base_type_exprs.extend(node.removed_base_type_exprs) node.removed_base_type_exprs = [] with self.enter_class(node.info): super().visit_class_def(node)
def analyze_namedtuple_classdef(self, defn: ClassDef) -> Optional[TypeInfo]: # special case for NamedTuple for base_expr in defn.base_type_exprs: if isinstance(base_expr, RefExpr): self.api.accept(base_expr) if base_expr.fullname == 'typing.NamedTuple': node = self.api.lookup(defn.name, defn) if node is not None: node.kind = GDEF # TODO in process_namedtuple_definition also applies here items, types, default_items = self.check_namedtuple_classdef(defn) info = self.build_namedtuple_typeinfo( defn.name, items, types, default_items) node.node = info defn.info.replaced = info defn.info = info defn.analyzed = NamedTupleExpr(info, is_typed=True) defn.analyzed.line = defn.line defn.analyzed.column = defn.column return info return None
def visit_class_def(self, node: ClassDef) -> None: """Strip class body and type info, but don't strip methods.""" # We need to save the implicitly defined instance variables, # i.e. those defined as attributes on self. Otherwise, they would # be lost if we only reprocess top-levels (this kills TypeInfos) # but not the methods that defined those variables. if not self.recurse_into_functions: self.prepare_implicit_var_patches(node) # We need to delete any entries that were generated by plugins, # since they will get regenerated. to_delete = {v.node for v in node.info.names.values() if v.plugin_generated} node.type_vars = [] node.base_type_exprs.extend(node.removed_base_type_exprs) node.removed_base_type_exprs = [] node.defs.body = [s for s in node.defs.body if s not in to_delete] with self.enter_class(node.info): super().visit_class_def(node) TypeState.reset_subtype_caches_for(node.info) # Kill the TypeInfo, since there is none before semantic analysis. node.info = CLASSDEF_NO_INFO
def visit_class_def(self, node: ClassDef) -> None: # TODO additional things? node.info = self.fixup_and_reset_typeinfo(node.info) node.defs.body = self.replace_statements(node.defs.body) info = node.info for tv in node.type_vars: self.process_type_var_def(tv) if info: if info.is_named_tuple: self.process_synthetic_type_info(info) else: self.process_type_info(info) super().visit_class_def(node)
def make_init_wrapper(self, tdef: ClassDef) -> List[Node]: """Make and return an implicit __init__ if class needs it. Otherwise, return an empty list. We include an implicit __init__ if the class is generic or if it extends a generic class and if it does not define __init__. The __init__ of a generic class requires one or more extra type variable arguments. The inherited __init__ may not accept these. For example, assume these definitions: . class A(Generic[T]): pass . class B(A[int]): pass The constructor for B will be (equivalent to) . def __init__(self: B) -> None: . self.__tv = <int> . super().__init__(<int>) """ # FIX overloading, default args / varargs, keyword args info = tdef.info if '__init__' not in info.names and ( tdef.is_generic() or (info.bases and info.mro[1].is_generic())): # Generic class with no explicit __init__ method # (i.e. __init__ inherited from superclass). Generate a # wrapper that initializes type variable slots and calls # the superclass __init__ method. base = info.mro[1] selftype = self_type(info) callee_type = cast(Callable, analyse_member_access( '__init__', selftype, None, False, True, None, None, base)) # Now the callee type may contain the type variables of a # grandparent as bound type variables, but we want the # type variables of the parent class. Explicitly set the # bound type variables. callee_type = self.fix_bound_init_tvars(callee_type, map_instance_to_supertype(selftype, base)) super_init = cast(FuncDef, base.get_method('__init__')) # Build argument list. args = [Var('self')] for i in range(1, len(super_init.args)): args.append(Var(super_init.args[i].name())) args[-1].type = callee_type.arg_types[i - 1] selft = self_type(self.tf.type_context()) callee_type = prepend_arg_type(callee_type, selft) creat = FuncDef('__init__', args, super_init.arg_kinds, [None] * len(args), Block([])) creat.info = tdef.info creat.type = callee_type creat.is_implicit = False tdef.info.names['__init__'] = SymbolTableNode(MDEF, creat, typ=creat.type) # Insert a call to superclass constructor. If the # superclass is object, the constructor does nothing => # omit the call. if base.fullname() != 'builtins.object': creat.body.body.append( self.make_superclass_constructor_call(tdef.info, callee_type)) # Implicit cast from FuncDef[] to Node[] is safe below. return Any(self.func_tf.transform_method(creat)) else: return []
def analyze_typeddict_classdef(self, defn: ClassDef) -> Tuple[bool, Optional[TypeInfo]]: """Analyze a class that may define a TypedDict. Assume that base classes have been analyzed already. Note: Unlike normal classes, we won't create a TypeInfo until the whole definition of the TypeDict (including the body and all key names and types) is complete. This is mostly because we store the corresponding TypedDictType in the TypeInfo. Return (is this a TypedDict, new TypeInfo). Specifics: * If we couldn't finish due to incomplete reference anywhere in the definition, return (True, None). * If this is not a TypedDict, return (False, None). """ possible = False for base_expr in defn.base_type_exprs: if isinstance(base_expr, RefExpr): self.api.accept(base_expr) if (base_expr.fullname == 'mypy_extensions.TypedDict' or self.is_typeddict(base_expr)): possible = True if possible: if (len(defn.base_type_exprs) == 1 and isinstance(defn.base_type_exprs[0], RefExpr) and defn.base_type_exprs[0].fullname == 'mypy_extensions.TypedDict'): # Building a new TypedDict fields, types, required_keys = self.analyze_typeddict_classdef_fields(defn) if fields is None: return True, None # Defer info = self.build_typeddict_typeinfo(defn.name, fields, types, required_keys) defn.analyzed = TypedDictExpr(info) defn.analyzed.line = defn.line defn.analyzed.column = defn.column return True, info # Extending/merging existing TypedDicts if any(not isinstance(expr, RefExpr) or expr.fullname != 'mypy_extensions.TypedDict' and not self.is_typeddict(expr) for expr in defn.base_type_exprs): self.fail("All bases of a new TypedDict must be TypedDict types", defn) typeddict_bases = list(filter(self.is_typeddict, defn.base_type_exprs)) keys = [] # type: List[str] types = [] required_keys = set() for base in typeddict_bases: assert isinstance(base, RefExpr) assert isinstance(base.node, TypeInfo) assert isinstance(base.node.typeddict_type, TypedDictType) base_typed_dict = base.node.typeddict_type base_items = base_typed_dict.items valid_items = base_items.copy() for key in base_items: if key in keys: self.fail('Cannot overwrite TypedDict field "{}" while merging' .format(key), defn) valid_items.pop(key) keys.extend(valid_items.keys()) types.extend(valid_items.values()) required_keys.update(base_typed_dict.required_keys) new_keys, new_types, new_required_keys = self.analyze_typeddict_classdef_fields(defn, keys) if new_keys is None: return True, None # Defer keys.extend(new_keys) types.extend(new_types) required_keys.update(new_required_keys) info = self.build_typeddict_typeinfo(defn.name, keys, types, required_keys) defn.analyzed = TypedDictExpr(info) defn.analyzed.line = defn.line defn.analyzed.column = defn.column return True, info return False, None
def analyze_typeddict_classdef(self, defn: ClassDef) -> bool: # special case for TypedDict possible = False for base_expr in defn.base_type_exprs: if isinstance(base_expr, RefExpr): self.api.accept(base_expr) if (base_expr.fullname == 'mypy_extensions.TypedDict' or self.is_typeddict(base_expr)): possible = True if possible: node = self.api.lookup(defn.name, defn) if node is not None: node.kind = GDEF # TODO in process_namedtuple_definition also applies here if (len(defn.base_type_exprs) == 1 and isinstance(defn.base_type_exprs[0], RefExpr) and defn.base_type_exprs[0].fullname == 'mypy_extensions.TypedDict'): # Building a new TypedDict fields, types, required_keys = self.check_typeddict_classdef(defn) info = self.build_typeddict_typeinfo(defn.name, fields, types, required_keys) defn.info.replaced = info defn.info = info node.node = info defn.analyzed = TypedDictExpr(info) defn.analyzed.line = defn.line defn.analyzed.column = defn.column return True # Extending/merging existing TypedDicts if any(not isinstance(expr, RefExpr) or expr.fullname != 'mypy_extensions.TypedDict' and not self.is_typeddict(expr) for expr in defn.base_type_exprs): self.fail("All bases of a new TypedDict must be TypedDict types", defn) typeddict_bases = list(filter(self.is_typeddict, defn.base_type_exprs)) keys = [] # type: List[str] types = [] required_keys = set() for base in typeddict_bases: assert isinstance(base, RefExpr) assert isinstance(base.node, TypeInfo) assert isinstance(base.node.typeddict_type, TypedDictType) base_typed_dict = base.node.typeddict_type base_items = base_typed_dict.items valid_items = base_items.copy() for key in base_items: if key in keys: self.fail('Cannot overwrite TypedDict field "{}" while merging' .format(key), defn) valid_items.pop(key) keys.extend(valid_items.keys()) types.extend(valid_items.values()) required_keys.update(base_typed_dict.required_keys) new_keys, new_types, new_required_keys = self.check_typeddict_classdef(defn, keys) keys.extend(new_keys) types.extend(new_types) required_keys.update(new_required_keys) info = self.build_typeddict_typeinfo(defn.name, keys, types, required_keys) defn.info.replaced = info defn.info = info node.node = info defn.analyzed = TypedDictExpr(info) defn.analyzed.line = defn.line defn.analyzed.column = defn.column return True return False