def testComplexCombinedType(self): """Test parsing a type with both union and intersection.""" data1 = r"def foo(a: Foo or Bar and Zot) -> object: ..." data2 = r"def foo(a: Foo or (Bar and Zot)) -> object: ..." result1 = self.Parse(data1) result2 = self.Parse(data2) f = pytd.Function( name="foo", signatures=(pytd.Signature(params=(pytd.Parameter( name="a", type=pytd.UnionType( type_list=(pytd.NamedType("Foo"), pytd.IntersectionType( type_list=(pytd.NamedType("Bar"), pytd.NamedType("Zot"))))), kwonly=False, optional=False, mutated_type=None), ), starargs=None, starstarargs=None, return_type=pytd.NamedType("object"), template=(), exceptions=()), ), kind=pytd.METHOD) self.assertEqual(f, result1.Lookup("foo")) self.assertEqual(f, result2.Lookup("foo"))
def p_type_and(self, p): """type : type AND type""" # TODO(kramm): Unless we bring interfaces back, it's not clear when # "type1 and type2" would be useful for anything. We # should remove it. # This rule depends on precedence specification # IntersectionType flattens any contained IntersectinType's p[0] = pytd.IntersectionType((p[1], p[3]))
def VisitGenericType(self, t): module, name = self._GetModuleAndName(t) if self._IsTyping(module): if name == "Intersection": return pytd.IntersectionType(t.parameters) elif name == "Optional": return pytd.UnionType(t.parameters + (pytd.NamedType("NoneType"),)) elif name == "Union": return pytd.UnionType(t.parameters) return t
def new_intersection_type(self, types): """Return a new IntersectionType composed of the specified types.""" # IntersectionType flattens any contained IntersectionType's. return pytd.IntersectionType(tuple(types))
def VisitIntersectionType(self, node): return pytd.IntersectionType(tuple(sorted(node.type_list)))