示例#1
0
    def test_very_mutual_recursion(self):
        ast = self._import(a="""
      from typing import List
      X = List[Y]
      Y = List[Z]
      Z = List[X]
    """)

        actual_x = ast.Lookup("a.X")
        expected_x = pytd.Alias(name="a.X",
                                type=pytd.GenericType(
                                    base_type=pytd.ClassType("builtins.list"),
                                    parameters=(pytd.LateType(
                                        "a.Y", recursive=True), )))
        self.assertEqual(actual_x, expected_x)

        actual_y = ast.Lookup("a.Y")
        expected_y = pytd.Alias(name="a.Y",
                                type=pytd.GenericType(
                                    base_type=pytd.ClassType("builtins.list"),
                                    parameters=(pytd.LateType(
                                        "a.Z", recursive=True), )))
        self.assertEqual(actual_y, expected_y)

        actual_z = ast.Lookup("a.Z")
        expected_z = pytd.Alias(
            name="a.Z",
            type=pytd.GenericType(
                base_type=pytd.ClassType("builtins.list"),
                parameters=(pytd.GenericType(
                    base_type=pytd.ClassType("builtins.list"),
                    parameters=(pytd.LateType("a.Y", recursive=True), )), )))
        self.assertEqual(actual_z, expected_z)
示例#2
0
 def test_basic(self):
     ast = self._import(a="""
   from typing import List
   X = List[X]
 """)
     actual_x = ast.Lookup("a.X")
     expected_x = pytd.Alias(name="a.X",
                             type=pytd.GenericType(
                                 base_type=pytd.ClassType("builtins.list"),
                                 parameters=(pytd.LateType(
                                     "a.X", recursive=True), )))
     self.assertEqual(actual_x, expected_x)
示例#3
0
 def testRemoveInheritedMethodsWithLateType(self):
     src = textwrap.dedent("""
     class Foo(other.Bar):
       def bar() -> float
 """)
     expected = textwrap.dedent("""
     class Foo(other.Bar):
       def bar() -> float
 """)
     ast = self.Parse(src)
     ast = ast.Visit(
         visitors.ReplaceTypes({"other.Bar": pytd.LateType("other.Bar")}))
     ast = ast.Visit(optimize.RemoveInheritedMethods())
     ast = ast.Visit(visitors.LateTypeToClassType())
     self.AssertSourceEquals(ast, expected)
示例#4
0
 def testFindCommonSuperClasses(self):
   src = textwrap.dedent("""
       x = ...  # type: int or other.Bar
   """)
   expected = textwrap.dedent("""
       x = ...  # type: int or other.Bar
   """)
   ast = self.Parse(src)
   ast = ast.Visit(visitors.ReplaceTypes(
       {"other.Bar": pytd.LateType("other.Bar")}))
   hierarchy = ast.Visit(visitors.ExtractSuperClassesByName())
   ast = ast.Visit(optimize.FindCommonSuperClasses(
       optimize.SuperClassHierarchy(hierarchy)))
   ast = ast.Visit(visitors.LateTypeToClassType())
   self.AssertSourceEquals(ast, expected)
示例#5
0
 def test_find_common_superclasses(self):
     src = pytd_src("""
     x = ...  # type: Union[int, other.Bar]
 """)
     expected = pytd_src("""
     x = ...  # type: Union[int, other.Bar]
 """)
     ast = self.Parse(src)
     ast = ast.Visit(
         visitors.ReplaceTypes({"other.Bar": pytd.LateType("other.Bar")}))
     hierarchy = ast.Visit(visitors.ExtractSuperClassesByName())
     ast = ast.Visit(
         optimize.FindCommonSuperClasses(
             optimize.SuperClassHierarchy(hierarchy)))
     ast = ast.Visit(visitors.LateTypeToClassType())
     self.AssertSourceEquals(ast, expected)
示例#6
0
 def test_anything_late(self):
     m = type_match.TypeMatch({})
     eq = m.match_type_against_type(pytd.AnythingType(), pytd.LateType("X"),
                                    {})
     self.assertEqual(eq, booleq.TRUE)
示例#7
0
 def test_named_late(self):
     m = type_match.TypeMatch({})
     eq = m.match_type_against_type(pytd.LateType("X"), pytd.NamedType("X"),
                                    {})
     self.assertEqual(eq, booleq.FALSE)
示例#8
0
    def value_instance_to_pytd_type(self, node, v, instance, seen, view):
        """Get the PyTD type an instance of this object would have.

    Args:
      node: The node.
      v: The object.
      instance: The instance.
      seen: Already seen instances.
      view: A Variable -> binding map.

    Returns:
      A PyTD type.
    """
        if abstract_utils.is_recursive_annotation(v):
            return pytd.LateType(
                v.unflatten_expr() if self._detailed else v.expr)
        elif isinstance(v, abstract.Union):
            return pytd.UnionType(
                tuple(
                    self.value_instance_to_pytd_type(node, t, instance, seen,
                                                     view) for t in v.options))
        elif isinstance(v, abstract.AnnotationContainer):
            return self.value_instance_to_pytd_type(node, v.base_cls, instance,
                                                    seen, view)
        elif isinstance(v, abstract.LiteralClass):
            if not v.value:
                # TODO(b/173742489): Remove this workaround once we support literal
                # enums.
                return pytd.AnythingType()
            if isinstance(v.value.pyval, (str, bytes)):
                # Strings are stored as strings of their representations, prefix and
                # quotes and all.
                value = repr(v.value.pyval)
            elif isinstance(v.value.pyval, bool):
                # True and False are stored as pytd constants.
                value = self.ctx.loader.lookup_builtin(
                    f"builtins.{v.value.pyval}")
            else:
                # Ints are stored as their literal values. Note that Literal[None] or a
                # nested literal will never appear here, since we simplified it to None
                # or unnested it, respectively, in typing_overlay. Literal[<enum>] does
                # not appear here yet because it is unsupported.
                assert isinstance(v.value.pyval, int), v.value.pyval
                value = v.value.pyval
            return pytd.Literal(value)
        elif isinstance(v, typed_dict.TypedDictClass):
            # TypedDict inherits from abstract.Dict for analysis purposes, but when
            # outputting to a pyi we do not want to treat it as a generic type.
            return pytd.NamedType(v.name)
        elif isinstance(v, abstract.Class):
            if not self._detailed and v.official_name is None:
                return pytd.AnythingType()
            if seen is None:
                # We make the set immutable to ensure that the seen instances for
                # different parameter values don't interfere with one another.
                seen = frozenset()
            if instance in seen:
                # We have a circular dependency in our types (e.g., lst[0] == lst). Stop
                # descending into the type parameters.
                type_params = ()
            else:
                type_params = tuple(t.name for t in v.template)
            if instance is not None:
                seen |= {instance}
            type_arguments = self._value_to_parameter_types(
                node, v, instance, type_params, seen, view)
            base = pytd_utils.NamedTypeWithModule(v.official_name or v.name,
                                                  v.module)
            if self._is_tuple(v, instance):
                homogeneous = False
            elif v.full_name == "typing.Callable":
                homogeneous = not isinstance(v, abstract.CallableClass)
            else:
                homogeneous = len(type_arguments) == 1
            return pytd_utils.MakeClassOrContainerType(base, type_arguments,
                                                       homogeneous)
        elif isinstance(v, abstract.TypeParameter):
            # We generate the full definition because, if this type parameter is
            # imported, we will need the definition in order to declare it later.
            return self._typeparam_to_def(node, v, v.name)
        elif isinstance(v, typing_overlay.NoReturn):
            return pytd.NothingType()
        else:
            log.info("Using Any for instance of %s", v.name)
            return pytd.AnythingType()