def _make_pytd_function(self, params): pytd_params = [] for i, p in enumerate(params): p_type = pytd.ClassType(p.name) p_type.cls = p pytd_params.append( pytd.Parameter("_" + str(i), p_type, False, False, None)) pytd_sig = pytd.Signature(tuple(pytd_params), None, None, pytd.AnythingType(), (), ()) sig = abstract.PyTDSignature("f", pytd_sig, self._vm) return abstract.PyTDFunction("f", (sig, ), pytd.METHOD, self._vm)
def test_compatible_with(self): pytd_sig = pytd.Signature((), None, None, pytd.AnythingType(), (), ()) sig = function.PyTDSignature("f", pytd_sig, self._vm) f = abstract.PyTDFunction("f", (sig, ), pytd.METHOD, self._vm) self.assertTruthy(f)
def construct_constant_from_value(self, name, pyval, subst, node): """Create a AtomicAbstractValue that represents a python constant. This supports both constant from code constant pools and PyTD constants such as classes. This also supports builtin python objects such as int and float. Args: name: The name of this constant. Used for naming its attribute variables. pyval: The python or PyTD value to convert. subst: The current type parameters. node: The current CFG node. Returns: A Value that represents the constant, or None if we couldn't convert. Raises: NotImplementedError: If we don't know how to convert a value. """ if pyval is type: return abstract.SimpleAbstractValue(name, self.vm) elif isinstance(pyval, str): return abstract.AbstractOrConcreteValue( pyval, self.str_type, self.vm, node) elif isinstance(pyval, int) and -1 <= pyval <= MAX_IMPORT_DEPTH: # For small integers, preserve the actual value (for things like the # level in IMPORT_NAME). return abstract.AbstractOrConcreteValue( pyval, self.int_type, self.vm, node) elif pyval.__class__ in self.primitive_classes: return self.primitive_class_instances[pyval.__class__] elif isinstance(pyval, (loadmarshal.CodeType, blocks.OrderedCode)): return abstract.AbstractOrConcreteValue( pyval, self.primitive_classes[types.CodeType], self.vm, node) elif pyval.__class__ in [types.FunctionType, types.ModuleType, types.GeneratorType, type]: try: pyclass = self.vm.vmbuiltins.Lookup("__builtin__." + pyval.__name__) return self.convert_constant_to_value(name, pyclass, subst, node) except (KeyError, AttributeError): log.debug("Failed to find pytd", exc_info=True) raise elif isinstance(pyval, pytd.TypeDeclUnit): data = pyval.constants + pyval.classes + pyval.functions + pyval.aliases members = {val.name.rsplit(".")[-1]: val for val in data} return abstract.Module(self.vm, node, pyval.name, members) elif isinstance(pyval, pytd.Class): if "." in pyval.name: module, base_name = pyval.name.rsplit(".", 1) cls = abstract.PyTDClass(base_name, pyval, self.vm) cls.module = module else: cls = abstract.PyTDClass(name, pyval, self.vm) return cls elif isinstance(pyval, pytd.Function): signatures = [abstract.PyTDSignature(pyval.name, sig, self.vm) for sig in pyval.signatures] f = abstract.PyTDFunction( pyval.name, signatures, pyval.kind, self.vm, node) return f elif isinstance(pyval, pytd.ClassType): assert pyval.cls return self.convert_constant_to_value(pyval.name, pyval.cls, subst, node) elif isinstance(pyval, pytd.NothingType): return self.nothing elif isinstance(pyval, pytd.AnythingType): # TODO(kramm): This should be an Unsolveable. We don't need to solve this. return self._create_new_unknown_value("AnythingType") elif isinstance(pyval, pytd.FunctionType): return self.construct_constant_from_value( name, pyval.function, subst, node) elif isinstance(pyval, pytd.UnionType): return abstract.Union([ self.convert_constant_to_value(pytd.Print(t), t, subst, node) for t in pyval.type_list], self.vm) elif isinstance(pyval, pytd.TypeParameter): return abstract.TypeParameter(pyval.name, self.vm) elif isinstance(pyval, abstract.AsInstance): cls = pyval.cls if isinstance(cls, pytd.ClassType): cls = cls.cls if isinstance(cls, pytd.Class): # This key is also used in __init__ key = (abstract.Instance, cls) if key not in self._convert_cache: if cls.name in ["__builtin__.type", "__builtin__.property"]: # An instance of "type" or of an anonymous property can be anything. instance = self._create_new_unknown_value("type") else: mycls = self.convert_constant(cls.name, cls, subst, node) instance = abstract.Instance(mycls, self.vm, node) log.info("New pytd instance for %s: %r", cls.name, instance) self._convert_cache[key] = instance return self._convert_cache[key] elif isinstance(cls, pytd.GenericType): assert isinstance(cls.base_type, pytd.ClassType) base_cls = cls.base_type.cls instance = abstract.Instance( self.convert_constant(base_cls.name, base_cls, subst, node), self.vm, node) for formal, actual in zip(base_cls.template, cls.parameters): p = self.convert_constant( repr(formal), abstract.AsInstance(actual), subst, node) instance.initialize_type_parameter(node, formal.name, p) return instance else: return self.convert_constant_to_value(name, cls, subst, node) elif isinstance(pyval, pytd.GenericType): assert isinstance(pyval.base_type, pytd.ClassType) type_parameters = utils.LazyDict() for param, value in zip(pyval.base_type.cls.template, pyval.parameters): type_parameters.add_lazy_item( param.name, self.convert_constant_to_value, param.name, value, subst, node) cls = self.convert_constant_to_value( pytd.Print(pyval.base_type), pyval.base_type.cls, subst, node) return abstract.ParameterizedClass(cls, type_parameters, self.vm) elif pyval.__class__ is tuple: # only match raw tuple, not namedtuple/Node return self.tuple_to_value(self.vm.root_cfg_node, [self.convert_constant("tuple[%d]" % i, item, subst, node) for i, item in enumerate(pyval)]) else: raise NotImplementedError("Can't convert constant %s %r" % (type(pyval), pyval))