def _infer_type_new_call(self, caller, context): """Try to infer what type.__new__(mcs, name, bases, attrs) returns. In order for such call to be valid, the metaclass needs to be a subtype of ``type``, the name needs to be a string, the bases needs to be a tuple of classes and the attributes a dictionary of strings to values. """ from astroid import node_classes # Verify the metaclass mcs = next(caller.args[0].infer(context=context)) if mcs.__class__.__name__ != 'ClassDef': # Not a valid first argument. return if not mcs.is_subtype_of("%s.type" % BUILTINS): # Not a valid metaclass. return # Verify the name name = next(caller.args[1].infer(context=context)) if name.__class__.__name__ != 'Const': # Not a valid name, needs to be a const. return if not isinstance(name.value, str): # Needs to be a string. return # Verify the bases bases = next(caller.args[2].infer(context=context)) if bases.__class__.__name__ != 'Tuple': # Needs to be a tuple. return inferred_bases = [ next(elt.infer(context=context)) for elt in bases.elts ] if any(base.__class__.__name__ != 'ClassDef' for base in inferred_bases): # All the bases needs to be Classes return # Verify the attributes. attrs = next(caller.args[3].infer(context=context)) if attrs.__class__.__name__ != 'Dict': # Needs to be a dictionary. return cls_locals = collections.defaultdict(list) for key, value in attrs.items: key = next(key.infer(context=context)) value = next(value.infer(context=context)) if key.__class__.__name__ != 'Const': # Something invalid as an attribute. return if not isinstance(key.value, str): # Not a proper attribute. return cls_locals[key.value].append(value) # Build the class from now. cls = mcs.__class__(name=name.value, lineno=caller.lineno, col_offset=caller.col_offset, parent=caller) empty = node_classes.Pass() cls.postinit(bases=bases.elts, body=[empty], decorators=[], newstyle=True, metaclass=mcs, keywords=[]) cls.locals = cls_locals return cls
def _infer_type_new_call(self, caller, context): """Try to infer what type.__new__(mcs, name, bases, attrs) returns. In order for such call to be valid, the metaclass needs to be a subtype of ``type``, the name needs to be a string, the bases needs to be a tuple of classes """ # pylint: disable=import-outside-toplevel; circular import from astroid import node_classes # Verify the metaclass mcs = next(caller.args[0].infer(context=context)) if mcs.__class__.__name__ != "ClassDef": # Not a valid first argument. return None if not mcs.is_subtype_of("%s.type" % BUILTINS): # Not a valid metaclass. return None # Verify the name name = next(caller.args[1].infer(context=context)) if name.__class__.__name__ != "Const": # Not a valid name, needs to be a const. return None if not isinstance(name.value, str): # Needs to be a string. return None # Verify the bases bases = next(caller.args[2].infer(context=context)) if bases.__class__.__name__ != "Tuple": # Needs to be a tuple. return None inferred_bases = [next(elt.infer(context=context)) for elt in bases.elts] if any(base.__class__.__name__ != "ClassDef" for base in inferred_bases): # All the bases needs to be Classes return None # Verify the attributes. attrs = next(caller.args[3].infer(context=context)) if attrs.__class__.__name__ != "Dict": # Needs to be a dictionary. return None cls_locals = collections.defaultdict(list) for key, value in attrs.items: key = next(key.infer(context=context)) value = next(value.infer(context=context)) # Ignore non string keys if key.__class__.__name__ == "Const" and isinstance(key.value, str): cls_locals[key.value].append(value) # Build the class from now. cls = mcs.__class__( name=name.value, lineno=caller.lineno, col_offset=caller.col_offset, parent=caller, ) empty = node_classes.Pass() cls.postinit( bases=bases.elts, body=[empty], decorators=[], newstyle=True, metaclass=mcs, keywords=[], ) cls.locals = cls_locals return cls