Exemplo n.º 1
0
 def testUnionTypeNe(self):
     u1 = pytd.UnionType((self.int, self.float))
     u2 = pytd.UnionType((self.float, self.int, self.none_type))
     self.assertNotEqual(u1, u2)
     self.assertNotEqual(u2, u1)
     self.assertEqual(u1.type_list, (self.int, self.float))
     self.assertEqual(u2.type_list, (self.float, self.int, self.none_type))
Exemplo n.º 2
0
 def p_type_or(self, p):
     """type : type OR type"""
     # This rule depends on precedence specification
     if (isinstance(p[1], pytd.UnionType)
             and isinstance(p[3], pytd.NamedType)):
         p[0] = pytd.UnionType(p[1].type_list + (p[3], ))
     elif (isinstance(p[1], pytd.NamedType)
           and isinstance(p[3], pytd.UnionType)):
         # associative
         p[0] = pytd.UnionType((p[1], ) + p[3].type_list)
     else:
         p[0] = pytd.UnionType((p[1], p[3]))
Exemplo n.º 3
0
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.

  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.

  Raises:
    ValueError: If you pass a malformed (i.e., empty) list.
  """
    if not types:
        raise ValueError("Can't join empty type list")

    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 t not in seen:
            new_types.append(t)
            seen.add(t)

    if len(new_types) == 1:
        return new_types.pop()
    else:
        return pytd.UnionType(
            tuple(new_types))  # tuple() to make unions hashable
Exemplo n.º 4
0
  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"))))
                    )
                ),),
            return_type=pytd.NamedType("object"),
            template=(), has_optional=False,
            exceptions=()),))
    self.assertEqual(f, result1.Lookup("foo"))
    self.assertEqual(f, result2.Lookup("foo"))
Exemplo n.º 5
0
 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)
Exemplo n.º 6
0
    def testUnionNone(self):
        """Type checking of function with None union.
    """
        self.assertEquals(3, union.IntOrNone(3))
        self.assertEquals(None, union.IntOrNone(None))

        with self.assertRaises(checker.CheckTypeAnnotationError) as context:
            union.IntOrNone("error")

        expected_param = checker.ParamTypeErrorMsg(
            "IntOrNone", "a", str, pytd.UnionType([int, type(None)]))

        expected_ret = checker.ReturnTypeErrorMsg(
            "IntOrNone", str, pytd.UnionType([int, type(None)]))

        [actual_param, actual_ret] = context.exception.args[0]
        self.assertEquals(expected_param, actual_param)
        self.assertEquals(expected_ret, actual_ret)
Exemplo n.º 7
0
  def setUp(self):
    self.bool = pytd.ClassType("bool")
    self.dict = pytd.ClassType("dict")
    self.float = pytd.ClassType("float")
    self.int = pytd.ClassType("int")
    self.list = pytd.ClassType("list")
    self.none_type = pytd.ClassType("NoneType")
    self.object = pytd.ClassType("object")
    self.str = pytd.ClassType("str")
    self.tuple = pytd.ClassType("tuple")

    self.intorfloat = pytd.UnionType((self.float, self.int))
    self.intorstr = pytd.UnionType((self.int, self.str))

    # Make get_pytd load _builtin_pytds
    self.builtin_pytds = parse.utils.GetBuiltins()
    for ty in (self.int, self.none_type, self.float,
               self.intorfloat, self.tuple, self.str,
               self.object, self.list, self.dict, self.bool):
      visitors.FillInClasses(ty, self.builtin_pytds)
Exemplo n.º 8
0
    def testUnionInReturnError(self):
        """Typechecking fct with union in return type (error).
    """
        with self.assertRaises(checker.CheckTypeAnnotationError) as context:
            union.UnionReturnError()

        expected = checker.ReturnTypeErrorMsg("UnionReturnError", tuple,
                                              pytd.UnionType([int, list]))

        [actual] = context.exception.args[0]
        self.assertEquals(expected, actual)
Exemplo n.º 9
0
    def testUnionError(self):
        """Type checking of function with union args (error).
    """

        with self.assertRaises(checker.CheckTypeAnnotationError) as context:
            union.IntOrFloat("1", 2)

        expected = checker.ParamTypeErrorMsg("IntOrFloat", "a", str,
                                             pytd.UnionType([int, float]))

        [actual] = context.exception.args[0]
        self.assertEquals(expected, actual)
Exemplo n.º 10
0
 def testListConcatMultiType(self):
     ty = self.InferDedent("""
   def f():
     x = []
     x.append(1)
     x.append("str")
     return x + [1.3] + x
   f()
 """)
     self.assertHasOnlySignatures(
         ty.Lookup("f"), ((),
                          pytd.GenericType(self.list, (pytd.UnionType(
                              (self.int, self.float, self.str)), ))))
Exemplo n.º 11
0
def ConvertToType(module, type_node):
  """Helper for converting a type node to a valid Python type.

  Args:
    module: The module to look up symbols/types
    type_node: A type node to convert into a python type

  Returns:
    A valid Python type. Note that None is considered a type in
    the declaration language, but a value in Python. So a string
    None is converted to a NoneType. We use the module object to look
    up potential type definitions defined inside that module.

  Raises:
    TypeError: if the type node passed is not supported/unknown
  """
  # TODO: Convert this to a visitor.

  # clean up str
  if isinstance(type_node, pytd.NamedType):
    if type_node.name == "None":
      return types.NoneType
    elif type_node.name == "generator":
      return types.GeneratorType
    else:
      res = _EvalWithModuleContext(type_node.name, module)
      assert isinstance(res, type), (type_node.name, repr(res))
      return res

  elif isinstance(type_node, pytd.UnionType):
    return pytd.UnionType([ConvertToType(module, t)
                           for t in type_node.type_list])

  elif isinstance(type_node, pytd.IntersectionType):
    return pytd.IntersectionType([ConvertToType(module, t)
                                  for t in type_node.type_list])

  elif isinstance(type_node, pytd.GenericType):
    return pytd.GenericType(ConvertToType(module,
                                          type_node.base_type),
                            type_node.parameters)

  elif isinstance(type_node, pytd.HomogeneousContainerType):
    return pytd.HomogeneousContainerType(ConvertToType(module,
                                                       type_node.base_type),
                                         ConvertToType(module,
                                                       type_node.element_type))

  else:
    raise TypeError("Unknown type of type_node: {!r}".format(type_node))
Exemplo n.º 12
0
    def testSimpleArgNoneAble(self):
        """Type checking of function with none-able argument."""
        # should work with no exceptions
        self.assertEquals(0, union.StrToInt(None))
        self.assertEquals(10, union.StrToInt("10"))

        with self.assertRaises(checker.CheckTypeAnnotationError) as context:
            union.StrToInt(10)  # can only pass str? so this should be an error

        expected = checker.ParamTypeErrorMsg("StrToInt", "s", int,
                                             pytd.UnionType([str,
                                                             type(None)]))

        [actual] = context.exception.args[0]
        self.assertEquals(expected, actual)
Exemplo n.º 13
0
 def testJoinTypes(self):
     """Test that JoinTypes() does recursive flattening."""
     n1, n2, n3, n4, n5, n6 = [pytd.NamedType("n%d" % i) for i in xrange(6)]
     # n1 or (n2 or (n3))
     nested1 = pytd.UnionType(
         (n1, pytd.UnionType((n2, pytd.UnionType((n3, ))))))
     # ((n4) or n5) or n6
     nested2 = pytd.UnionType((pytd.UnionType((pytd.UnionType(
         (n4, )), n5)), n6))
     joined = optimize.JoinTypes([nested1, nested2])
     self.assertEquals(joined.type_list, (n1, n2, n3, n4, n5, n6))
Exemplo n.º 14
0
    def testUnionWithClassTypes(self):
        """Type checking of function with union and class types.
    """

        self.assertEquals(None, union.AppleOrBananaOrOrange(simple.Apple()))
        self.assertEquals(None, union.AppleOrBananaOrOrange(simple.Banana()))
        self.assertEquals(None, union.AppleOrBananaOrOrange(simple.Orange()))

        with self.assertRaises(checker.CheckTypeAnnotationError) as context:
            union.AppleOrBananaOrOrange(42)

        expected = checker.ParamTypeErrorMsg(
            "AppleOrBananaOrOrange", "f", int,
            pytd.UnionType([simple.Apple, simple.Banana, simple.Orange]))

        [actual] = context.exception.args[0]
        self.assertEquals(expected, actual)
Exemplo n.º 15
0
    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
Exemplo n.º 16
0
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()
Exemplo n.º 17
0
 def VisitUnionType(self, node):
     return pytd.UnionType(tuple(sorted(node.type_list)))
Exemplo n.º 18
0
 def p_type_or(self, p):
     """type : type OR type"""
     # This rule depends on precedence specification
     # UnionType flattens any contained UnionType's
     p[0] = pytd.UnionType((p[1], p[3]))