def testTuplePassThrough(self): ty = self.Infer(""" def f(x): return x f((3, "str")) """, deep=False, solve_unknowns=False, extract_locals=False) self.assertHasOnlySignatures( ty.Lookup("f"), ((pytd.HomogeneousContainerType(self.tuple, (self.intorstr, )), ), pytd.HomogeneousContainerType(self.tuple, (self.intorstr, ))))
def testTupleSwap(self): with self.Infer(""" def f(x): return (x[1], x[0]) f((3, "str")) """, deep=False, solve_unknowns=False, extract_locals=False) as ty: self.assertHasOnlySignatures( ty.Lookup("f"), ((pytd.HomogeneousContainerType(self.tuple, (self.intorstr, )), ), pytd.HomogeneousContainerType(self.tuple, (self.intorstr, ))))
def testTypingContainer(self): cls = self._vm.convert.list_type.bindings[0].data container = abstract.AnnotationContainer("List", self._vm, cls) expected = pytd.HomogeneousContainerType( pytd.NamedType("__builtin__.list"), (pytd.AnythingType(), )) actual = container.get_instance_type(self._vm.root_cfg_node) self.assertEquals(expected, actual)
def convert_string_type(string_type, unknown, mapping, global_lookup, depth=0): """Convert a string representing a type back to a pytd type.""" try: # Check whether this is a type declared in a pytd. cls = global_lookup.Lookup(string_type) base_type = pytd_utils.NamedOrClassType(cls.name, cls) except KeyError: # If we don't have a pytd for this type, it can't be a template. cls = None base_type = pytd_utils.NamedOrClassType(string_type, cls) if cls and cls.template: parameters = [] for t in cls.template: type_param_name = unknown + "." + string_type + "." + t.name if type_param_name in mapping and depth < MAX_DEPTH: string_type_params = mapping[type_param_name] parameters.append( convert_string_type_list(string_type_params, unknown, mapping, global_lookup, depth + 1)) else: parameters.append(pytd.AnythingType()) if len(parameters) == 1: return pytd.HomogeneousContainerType(base_type, tuple(parameters)) else: return pytd.GenericType(base_type, tuple(parameters)) else: return base_type
def MakeClassOrContainerType(base_type, type_arguments): """If we have type params, build a generic type, a normal type otherwise.""" if len(type_arguments) == 0: return base_type elif len(type_arguments) == 1: return pytd.HomogeneousContainerType(base_type, tuple(type_arguments)) else: return pytd.GenericType(base_type, tuple(type_arguments))
def _star_param(name, param_type): """Return a pytd.Parameter for a *args argument.""" if param_type is None: param_type = pytd.NamedType("tuple") else: param_type = pytd.HomogeneousContainerType(pytd.NamedType("tuple"), (param_type, )) return pytd.Parameter(name, param_type, False, True, None)
def testListLiteral(self): ty = self.Infer(""" def f(): return [1, 2, 3] f() """, deep=False, solve_unknowns=False, show_library_calls=True) self.assertHasOnlySignatures( ty.Lookup("f"), ((), pytd.HomogeneousContainerType(self.list, (self.int,))))
def testEmptyTuple(self): ty = self.Infer(""" def f(): return () f() """, deep=False, solve_unknowns=False, show_library_calls=True) self.assertHasOnlySignatures( ty.Lookup("f"), ((), pytd.HomogeneousContainerType(self.tuple, (pytd.NothingType(),))))
def MakeClassOrContainerType(base_type, type_arguments, homogeneous): """If we have type params, build a generic type, a normal type otherwise.""" if homogeneous: assert len(type_arguments) == 1 return pytd.HomogeneousContainerType(base_type, tuple(type_arguments)) elif base_type.name in ("__builtin__.tuple", "typing.Tuple"): return pytd.TupleType(base_type, tuple(type_arguments)) elif not type_arguments: return base_type else: return pytd.GenericType(base_type, tuple(type_arguments))
def testSetsSanity(self): ty = self.Infer(""" def f(): x = set([1]) x.add(10) return x f() """, deep=False, solve_unknowns=False, show_library_calls=True) self.assertHasOnlySignatures( ty.Lookup("f"), ((), pytd.HomogeneousContainerType(self.set, (self.int,))))
def testListLiteral(self): with self.Infer(""" def f(): return [1, 2, 3] f() """, deep=False, solve_unknowns=False, extract_locals=False) as ty: self.assertHasOnlySignatures( ty.Lookup("f"), ((), pytd.HomogeneousContainerType(self.list, (self.int, ))))
def testListConcatUnlike(self): ty = self.Infer(""" def f(): x = [] x.append(1) x.append(2) x.append(3) return ["str"] + x f() """, deep=False, solve_unknowns=False, show_library_calls=True) self.assertHasOnlySignatures( ty.Lookup("f"), ((), pytd.HomogeneousContainerType(self.list, (self.intorstr,))))
def testEmptyTuple(self): with self.Infer(""" def f(): return () f() """, deep=False, solve_unknowns=False, extract_locals=False) as ty: self.assertHasOnlySignatures( ty.Lookup("f"), ((), pytd.HomogeneousContainerType(self.tuple, (pytd.NothingType(), ))))
def testSetsAdd(self): ty = self.Infer(""" def f(): x = set([]) x.add(1) x.add(10) return x f() """, deep=False, solve_unknowns=False, extract_locals=False) self.assertHasOnlySignatures( ty.Lookup("f"), ((), pytd.HomogeneousContainerType(self.set, (self.int, ))))
def testListConcatMultiType(self): ty = self.Infer(""" def f(): x = [] x.append(1) x.append("str") return x + [1.3] + x f() """, deep=False, solve_unknowns=False, show_library_calls=True) self.assertHasOnlySignatures( ty.Lookup("f"), ((), pytd.HomogeneousContainerType( self.list, (pytd.UnionType((self.int, self.float, self.str)),))))
def testSetsSanity(self): with self.Infer(""" def f(): x = set([1]) x.add(10) return x f() """, deep=False, solve_unknowns=False, extract_locals=False) as ty: self.assertHasOnlySignatures( ty.Lookup("f"), ((), pytd.HomogeneousContainerType(pytd.ClassType("set"), (self.int, ))))
def testListConcat(self): with self.Infer(""" def f(): x = [] x.append(1) x.append(2) x.append(3) return [0] + x f() """, deep=False, solve_unknowns=False, extract_locals=False) as ty: self.assertHasOnlySignatures( ty.Lookup("f"), ((), pytd.HomogeneousContainerType(self.list, (self.int, ))))
def p_type_homogeneous(self, p): """type : named_or_external_type LBRACKET parameters RBRACKET""" _, base_type, _, parameters, _ = p if p[1] == pytd.NamedType('Union'): p[0] = pytd.UnionType(parameters) elif p[1] == pytd.NamedType('Optional'): p[0] = pytd.UnionType(parameters[0], pytd.NamedType('None')) elif len(parameters) == 2 and parameters[-1] is Ellipsis: element_type, _ = parameters if element_type is Ellipsis: make_syntax_error(self, '[..., ...] not supported', p) p[0] = pytd.HomogeneousContainerType(base_type=base_type, parameters=(element_type, )) else: parameters = tuple(pytd.AnythingType() if p is Ellipsis else p for p in parameters) p[0] = pytd.GenericType(base_type=base_type, parameters=parameters)
def _parameterized_type(self, base_type, parameters): """Return a parameterized type.""" if base_type == pytd.NamedType("typing.Callable"): # TODO(kramm): Support Callable[[params], ret]. return base_type elif len(parameters) == 2 and parameters[-1] is self.ELLIPSIS: element_type = parameters[0] if element_type is self.ELLIPSIS: raise ParseError("[..., ...] not supported") return pytd.HomogeneousContainerType(base_type=base_type, parameters=(element_type, )) else: parameters = tuple(pytd.AnythingType() if p is self.ELLIPSIS else p for p in parameters) if self._is_tuple_base_type(base_type): return self._heterogeneous_tuple(base_type, parameters) else: assert parameters return pytd.GenericType(base_type=base_type, parameters=parameters)
def setUp(self): self.bool = pytd.ClassType("bool") self.dict = pytd.ClassType("dict") self.float = pytd.ClassType("float") self.complex = pytd.ClassType("complex") self.int = pytd.ClassType("int") if self.PYTHON_VERSION[0] == 2: self.long = pytd.ClassType("long") self.list = pytd.ClassType("list") self.none_type = pytd.ClassType("NoneType") self.object = pytd.ClassType("object") self.set = pytd.ClassType("set") self.frozenset = pytd.ClassType("frozenset") self.str = pytd.ClassType("str") self.bytes = pytd.ClassType("bytes") self.bytearray = pytd.ClassType("bytearray") self.tuple = pytd.ClassType("tuple") self.unicode = pytd.ClassType("unicode") self.generator = pytd.ClassType("generator") self.function = pytd.ClassType("function") self.anything = pytd.AnythingType() self.nothing = pytd.NothingType() self.module = pytd.ClassType("module") self.file = pytd.ClassType("file") # The various union types use pytd_utils.CanonicalOrdering()'s ordering: self.intorstr = pytd.UnionType((self.int, self.str)) self.strorunicodeorbytes = pytd.UnionType( (self.str, self.unicode, self.bytes)) self.intorfloat = pytd.UnionType((self.float, self.int)) self.intorfloatorstr = pytd.UnionType((self.float, self.int, self.str)) self.complexorstr = pytd.UnionType((self.complex, self.str)) # TODO(pludemann): fix the boolorintor... stuff when __builtins__ # is modified to exclude bool from the result if self.PYTHON_VERSION[0] == 3: self.intorfloatorlong = self.intorfloat self.intorfloatorlongorcomplex = pytd.UnionType( (self.int, self.float, self.complex)) else: self.intorfloatorlong = pytd.UnionType((self.int, self.float, self.long)) self.boolorintorfloatorlongorcomplex = pytd.UnionType( (self.bool, self.int, self.float, self.long, self.complex)) self.int_tuple = pytd.HomogeneousContainerType(self.tuple, (self.int,)) self.nothing_tuple = pytd.HomogeneousContainerType(self.tuple, (self.nothing,)) self.intorfloat_tuple = pytd.HomogeneousContainerType(self.tuple, (self.intorfloat,)) self.int_set = pytd.HomogeneousContainerType(self.set, (self.int,)) self.intorfloat_set = pytd.HomogeneousContainerType(self.set, (self.intorfloat,)) # TODO(pludemann): simplify this (test_and2) self.unknown_frozenset = pytd.HomogeneousContainerType( self.frozenset, (self.anything,)) self.float_frozenset = pytd.HomogeneousContainerType(self.frozenset, (self.float,)) self.empty_frozenset = pytd.HomogeneousContainerType(self.frozenset, (self.nothing,)) self.int_list = pytd.HomogeneousContainerType(self.list, (self.int,)) self.str_list = pytd.HomogeneousContainerType(self.list, (self.str,)) self.intorfloat_list = pytd.HomogeneousContainerType(self.list, (self.intorfloat,)) self.intorstr_list = pytd.HomogeneousContainerType(self.list, (self.intorstr,)) self.anything_list = pytd.HomogeneousContainerType(self.list, (self.anything,)) self.nothing_list = pytd.HomogeneousContainerType(self.list, (self.nothing,)) self.int_int_dict = pytd.GenericType(self.dict, (self.int, self.int)) self.int_str_dict = pytd.GenericType(self.dict, (self.int, self.str)) self.str_int_dict = pytd.GenericType(self.dict, (self.str, self.int)) self.nothing_nothing_dict = pytd.GenericType(self.dict, (self.nothing, self.nothing))
def VisitUnionType(self, union): """Push unions down into containers. This collects similar container types in unions and merges them into single instances with the union type pushed down to the element_type level. Arguments: union: A pytd.Union instance. Might appear in a parameter, a return type, a constant type, etc. Returns: A simplified pytd.Union. """ if not any(isinstance(t, pytd.GenericType) for t in union.type_list): # Optimization: If we're not going to change anything, return original. return union union = utils.JoinTypes(union.type_list) # flatten if not isinstance(union, pytd.UnionType): union = pytd.UnionType((union,)) merge_tuples = True tuple_length = None for t in union.type_list: if isinstance(t, pytd.TupleType): if tuple_length is None: tuple_length = len(t.parameters) elif tuple_length != len(t.parameters): break elif (isinstance(t, pytd.HomogeneousContainerType) and t.base_type.name in ("__builtin__.tuple", "typing.Tuple")): break else: merge_tuples = False if merge_tuples: # If our union contains homogeneous tuples, or heterogeneous tuples of # differing lengths, we want to turn all of the tuples into homogeneous # ones so that they can be merged into a single container. type_list = tuple( pytd.HomogeneousContainerType( base_type=t.base_type, parameters=(pytd.UnionType(t.parameters),)) if isinstance(t, pytd.TupleType) else t for t in union.type_list) union = union.Replace(type_list=type_list) collect = {} has_redundant_base_types = False for t in union.type_list: if isinstance(t, pytd.GenericType): key = self._key(t) if key in collect: has_redundant_base_types = True collect[key] = tuple( utils.JoinTypes([p1, p2]) for p1, p2 in zip(collect[key], t.parameters)) else: collect[key] = t.parameters if not has_redundant_base_types: return union result = pytd.NothingType() done = set() for t in union.type_list: if isinstance(t, pytd.GenericType): key = self._key(t) if key in done: continue # already added parameters = collect[key] add = t.Replace(parameters=tuple(p.Visit(CombineContainers()) for p in parameters)) done.add(key) else: add = t result = utils.JoinTypes([result, add]) return result
def setUp(self): self.options = config.Options.create(python_version=self.PYTHON_VERSION, python_exe=self.PYTHON_EXE) def t(name): # pylint: disable=invalid-name return pytd.ClassType("__builtin__." + name) self.bool = t("bool") self.dict = t("dict") self.float = t("float") self.complex = t("complex") self.int = t("int") if self.PYTHON_VERSION[0] == 2: self.long = t("long") self.list = t("list") self.none_type = t("NoneType") self.object = t("object") self.set = t("set") self.frozenset = t("frozenset") self.str = t("str") self.bytearray = t("bytearray") self.tuple = t("tuple") self.unicode = t("unicode") self.generator = t("generator") self.function = t("function") self.anything = pytd.AnythingType() self.nothing = pytd.NothingType() self.module = t("module") self.file = t("file") # The various union types use pytd_utils.CanonicalOrdering()'s ordering: self.intorstr = pytd.UnionType((self.int, self.str)) self.strorunicode = pytd.UnionType((self.str, self.unicode)) self.intorfloat = pytd.UnionType((self.float, self.int)) self.intorfloatorstr = pytd.UnionType((self.float, self.int, self.str)) self.complexorstr = pytd.UnionType((self.complex, self.str)) if self.PYTHON_VERSION[0] == 3: self.intorfloatorlong = self.intorfloat self.intorfloatorlongorcomplex = pytd.UnionType( (self.int, self.float, self.complex)) else: self.intorfloatorlong = pytd.UnionType((self.int, self.float, self.long)) self.intorfloatorlongorcomplex = pytd.UnionType( (self.int, self.float, self.long, self.complex)) self.int_tuple = pytd.HomogeneousContainerType(self.tuple, (self.int,)) self.nothing_tuple = pytd.HomogeneousContainerType(self.tuple, (self.nothing,)) self.intorfloat_tuple = pytd.HomogeneousContainerType(self.tuple, (self.intorfloat,)) self.int_set = pytd.HomogeneousContainerType(self.set, (self.int,)) self.intorfloat_set = pytd.HomogeneousContainerType(self.set, (self.intorfloat,)) # TODO(pludemann): simplify this (test_and2) self.unknown_frozenset = pytd.HomogeneousContainerType( self.frozenset, (self.anything,)) self.float_frozenset = pytd.HomogeneousContainerType(self.frozenset, (self.float,)) self.empty_frozenset = pytd.HomogeneousContainerType(self.frozenset, (self.nothing,)) self.int_list = pytd.HomogeneousContainerType(self.list, (self.int,)) self.str_list = pytd.HomogeneousContainerType(self.list, (self.str,)) self.intorfloat_list = pytd.HomogeneousContainerType(self.list, (self.intorfloat,)) self.intorstr_list = pytd.HomogeneousContainerType(self.list, (self.intorstr,)) self.anything_list = pytd.HomogeneousContainerType(self.list, (self.anything,)) self.nothing_list = pytd.HomogeneousContainerType(self.list, (self.nothing,)) self.int_int_dict = pytd.GenericType(self.dict, (self.int, self.int)) self.int_str_dict = pytd.GenericType(self.dict, (self.int, self.str)) self.str_int_dict = pytd.GenericType(self.dict, (self.str, self.int)) self.nothing_nothing_dict = pytd.GenericType(self.dict, (self.nothing, self.nothing))