def testJoinNothingType(self): """Test that JoinTypes() removes or collapses 'nothing'.""" a = pytd.NamedType("a") nothing = pytd.NothingType() self.assertEquals(utils.JoinTypes([a, nothing]), a) self.assertEquals(utils.JoinTypes([nothing]), nothing) self.assertEquals(utils.JoinTypes([nothing, nothing]), nothing)
def p_classdef(self, p): """classdef : CLASS NAME template parents COLON INDENT class_funcs DEDENT""" # 1 2 3 4 5 6 funcdefs = [x for x in p[7] if isinstance(x, NameAndSig)] constants = [x for x in p[7] if isinstance(x, pytd.Constant)] if (set(f.name for f in funcdefs) | set(c.name for c in constants) != set(d.name for d in p[7])): # TODO: raise a syntax error right when the identifier is defined. raise make_syntax_error(self, 'Duplicate identifier(s)', p) # Check that template parameter names are unique: template_names = {t.name for t in p[3]} for _, sig in funcdefs: for t in sig.template: if t.name in template_names: raise make_syntax_error( self, 'Duplicate template parameter %s' % t.name, p) if p[4] == [pytd.NothingType()]: bases = () else: # Everything implicitly subclasses "object" bases = tuple(p[4]) or (pytd.NamedType('object'), ) cls = pytd.Class(name=p[2], parents=bases, methods=tuple(MergeSignatures(funcdefs)), constants=tuple(constants), template=tuple(p[3])) p[0] = cls.Visit(visitors.AdjustSelf())
def testEmptyTuple(self): ty = self.InferDedent(""" def f(): return () f() """) self.assertHasOnlySignatures(ty.Lookup("f"), ((), pytd.GenericType(self.tuple, (pytd.NothingType(),))))
def testOrder(self): # pytd types' primary sort key is the class name, second sort key is # the contents when interpreted as a (named)tuple. nodes = [ pytd.AnythingType(), pytd.GenericType(self.list, (self.int, )), pytd.NamedType("int"), pytd.NothingType(), pytd.UnionType(self.float), pytd.UnionType(self.int) ] for n1, n2 in zip(nodes[:-1], nodes[1:]): self.assertLess(n1, n2) self.assertLessEqual(n1, n2) self.assertGreater(n2, n1) self.assertGreaterEqual(n2, n1) for p in itertools.permutations(nodes): self.assertEquals(list(sorted(p)), nodes)
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, )) collect = {} for t in union.type_list: if isinstance(t, pytd.GenericType): if t.base_type in collect: collect[t.base_type] = tuple( utils.JoinTypes([p1, p2]) for p1, p2 in zip(collect[t.base_type], t.parameters)) else: collect[t.base_type] = t.parameters result = pytd.NothingType() done = set() for t in union.type_list: if isinstance(t, pytd.GenericType): if t.base_type in done: continue # already added add = t.Replace(parameters=collect[t.base_type]) done.add(t.base_type) else: add = t result = utils.JoinTypes([result, add]) return result
def testTypeMatcher(self): """Test for the TypeMatcher class.""" class MyTypeMatcher(utils.TypeMatcher): def default_match(self, t1, t2, mykeyword): assert mykeyword == "foobar" return t1 == t2 def match_function_against_function(self, f1, f2, mykeyword): assert mykeyword == "foobar" return all( self.match(sig1, sig2, mykeyword) for sig1, sig2 in zip(f1.signatures, f2.signatures)) s1 = pytd.Signature((), pytd.NothingType(), (), (), False) s2 = pytd.Signature((), pytd.AnythingType(), (), (), False) match1 = MyTypeMatcher().match(pytd.Function("f1", (s1, s2)), pytd.Function("f2", (s1, s2)), mykeyword="foobar") self.assertEquals(match1, True) match2 = MyTypeMatcher().match(pytd.Function("f1", (s1, s2)), pytd.Function("f2", (s2, s2)), mykeyword="foobar") self.assertEquals(match2, False)
def JoinTypes(types): """Combine a list of types into a union type, if needed. Leaves singular return values alone, or wraps a UnionType around them if there are multiple ones, or if there are no elements in the list (or only NothingType) return NothingType. Arguments: types: A list of types. This list might contain other UnionTypes. If so, they are flattened. Returns: A type that represents the union of the types passed in. Order is preserved. """ queue = collections.deque(types) seen = set() new_types = [] while queue: t = queue.popleft() if isinstance(t, pytd.UnionType): queue.extendleft(reversed(t.type_list)) elif isinstance(t, pytd.NothingType): pass elif t not in seen: new_types.append(t) seen.add(t) if len(new_types) == 1: return new_types.pop() elif any(isinstance(t, pytd.AnythingType) for t in new_types): return pytd.AnythingType() elif new_types: return pytd.UnionType( tuple(new_types)) # tuple() to make unions hashable else: return pytd.NothingType()
def p_type_nothing(self, p): """type : NOTHING""" p[0] = pytd.NothingType()
def testNothing(self): m = type_match.TypeMatch({}) eq = m.match_type_against_type(pytd.NothingType(), pytd.NamedType("A"), {}) self.assertEquals(eq, booleq.FALSE)