Example #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)
Example #2
0
    def testClassSanity(self):
        ty = self.Infer("""
      class A(object):
        def __init__(self):
          self.x = 1

        def get_x(self):
          return self.x

        def set_x(self, x):
          self.x = x
      a = A()
      y = a.x
      x1 = a.get_x()
      a.set_x(1.2)
      x2 = a.get_x()
    """,
                        deep=False,
                        solve_unknowns=False,
                        extract_locals=False)
        self.assertHasSignature(
            ty.Lookup("A").Lookup("set_x"), (pytd.ClassType("A"), self.float),
            self.none_type)
        self.assertHasSignature(
            ty.Lookup("A").Lookup("get_x"), (pytd.ClassType("A"), ),
            self.intorfloat)
Example #3
0
 def match_Generic_against_Generic(self, t1, t2, subst):  # pylint: disable=invalid-name
     """Match a pytd.GenericType against another pytd.GenericType."""
     assert isinstance(t1.base_type, pytd.ClassType), type(t1.base_type)
     assert isinstance(t2.base_type, pytd.ClassType), type(t2.base_type)
     base1 = pytd.ClassType(t1.base_type.cls.name, t1.base_type.cls)
     base2 = pytd.ClassType(t2.base_type.cls.name, t2.base_type.cls)
     base_type_cmp = self.match_type_against_type(base1, base2, subst)
     if base_type_cmp is booleq.FALSE:
         return booleq.FALSE
     if not isinstance(t1, pytd.TupleType) and isinstance(
             t2, pytd.TupleType):
         p1, = t1.parameters
         param_cmp = [
             self.match_type_against_type(p1, p2, subst)
             for p2 in t2.parameters
         ]
     else:
         t1_parameters = t1.parameters
         if isinstance(t1, pytd.TupleType):
             if isinstance(t2, pytd.TupleType):
                 if len(t1_parameters) != len(t2.parameters):
                     return booleq.FALSE
             else:
                 t1_parameters = (pytd.UnionType(type_list=t1_parameters), )
         # Matching, e.g., Dict[str, int] against Iterable[K] is legitimate.
         assert len(t1_parameters) >= len(
             t2.parameters), t1.base_type.cls.name
         # Type parameters are covariant:
         # E.g. passing list[int] as argument for list[object] succeeds.
         param_cmp = [
             self.match_type_against_type(p1, p2, subst)
             for p1, p2 in zip(t1_parameters, t2.parameters)
         ]
     return booleq.And([base_type_cmp] + param_cmp)
Example #4
0
 def testAdjustTypeParametersWithBuiltins(self):
   ast = self.ParseWithBuiltins("""
     T = TypeVar("T")
     K = TypeVar("K")
     V = TypeVar("V")
     class Foo(List[int]): pass
     class Bar(Dict[T, int]): pass
     class Baz(Generic[K, V]): pass
     class Qux(Baz[str, int]): pass
   """)
   foo = ast.Lookup("Foo")
   bar = ast.Lookup("Bar")
   qux = ast.Lookup("Qux")
   foo_parent, = foo.parents
   bar_parent, = bar.parents
   qux_parent, = qux.parents
   # Expected:
   #  Class(Foo, parent=GenericType(List, parameters=(int,)), template=())
   #  Class(Bar, parent=GenericType(Dict, parameters=(T, int)), template=(T))
   #  Class(Qux, parent=GenericType(Baz, parameters=(str, int)), template=())
   self.assertEqual((pytd.ClassType("int"),), foo_parent.parameters)
   self.assertEqual((), foo.template)
   self.assertEqual(
       (pytd.TypeParameter("T", scope="Bar"), pytd.ClassType("int")),
       bar_parent.parameters)
   self.assertEqual(
       (pytd.TemplateItem(pytd.TypeParameter("T", scope="Bar")),),
       bar.template)
   self.assertEqual((pytd.ClassType("str"), pytd.ClassType("int")),
                    qux_parent.parameters)
   self.assertEqual((), qux.template)
Example #5
0
 def testMaybeInPlaceFillInClasses(self):
   src = textwrap.dedent("""
       class A(object):
           def a(self, a: A, b: B) -> A or B raises A, B
   """)
   tree = self.Parse(src)
   ty_a = pytd.ClassType("A")
   visitors.InPlaceFillInClasses(ty_a, tree)
   self.assertIsNotNone(ty_a.cls)
   ty_b = pytd.ClassType("B")
   visitors.InPlaceFillInClasses(ty_b, tree)
   self.assertIsNone(ty_b.cls)
Example #6
0
 def testMaybeFillInLocalPointers(self):
   src = textwrap.dedent("""
       class A(object):
           def a(self, a: A, b: B) -> A or B:
               raise A()
               raise B()
   """)
   tree = self.Parse(src)
   ty_a = pytd.ClassType("A")
   ty_a.Visit(visitors.FillInLocalPointers({"": tree}))
   self.assertIsNotNone(ty_a.cls)
   ty_b = pytd.ClassType("B")
   ty_b.Visit(visitors.FillInLocalPointers({"": tree}))
   self.assertIsNone(ty_b.cls)
Example #7
0
 def test_maybe_fill_in_local_pointers(self):
     src = textwrap.dedent("""
     from typing import Union
     class A:
         def a(self, a: A, b: B) -> Union[A, B]:
             raise A()
             raise B()
 """)
     tree = self.Parse(src)
     ty_a = pytd.ClassType("A")
     ty_a.Visit(visitors.FillInLocalPointers({"": tree}))
     self.assertIsNotNone(ty_a.cls)
     ty_b = pytd.ClassType("B")
     ty_b.Visit(visitors.FillInLocalPointers({"": tree}))
     self.assertIsNone(ty_b.cls)
Example #8
0
 def _load_late_type(self, late_type):
     """Resolve a late type, possibly by loading a module."""
     if late_type.name not in self._resolved_late_types:
         module, dot, _ = late_type.name.rpartition(".")
         assert dot
         ast = self.vm.loader.import_name(module)
         if ast is not None:
             try:
                 # TODO(kramm): Should this use visitor.py:ToType?
                 cls = ast.Lookup(late_type.name)
             except KeyError:
                 try:
                     ast.Lookup("__getattr__")
                 except KeyError:
                     log.warning("Couldn't resolve %s", late_type.name)
                 t = pytd.AnythingType()
             else:
                 assert isinstance(cls, pytd.Class)
                 t = pytd.ClassType(late_type.name, cls)
         else:
             # A pickle file refers to a module that went away in the mean time.
             log.error("During dependency resolution, couldn't import %r",
                       module)
             t = pytd.AnythingType()
         self._resolved_late_types[late_type.name] = t
     return self._resolved_late_types[late_type.name]
Example #9
0
 def match_Generic_against_Generic(self, t1, t2, subst):  # pylint: disable=invalid-name
     """Match a pytd.GenericType against another pytd.GenericType."""
     assert isinstance(t1.base_type, pytd.ClassType), type(t1.base_type)
     assert isinstance(t2.base_type, pytd.ClassType), type(t2.base_type)
     base1 = pytd.ClassType(t1.base_type.cls.name, t1.base_type.cls)
     base2 = pytd.ClassType(t2.base_type.cls.name, t2.base_type.cls)
     base_type_cmp = self.match_type_against_type(base1, base2, subst)
     if base_type_cmp is booleq.FALSE:
         return booleq.FALSE
     assert len(t1.parameters) == len(t2.parameters), t1.base_type.cls.name
     # Type parameters are covariant:
     # E.g. passing list[int] as argument for list[object] succeeds.
     param_cmp = [
         self.match_type_against_type(p1, p2, subst)
         for p1, p2 in zip(t1.parameters, t2.parameters)
     ]
     return booleq.And([base_type_cmp] + param_cmp)
Example #10
0
 def testParsePyTD(self):
     """Test ParsePyTD()."""
     ast = utils.ParsePyTD("a = ...  # type: int",
                           "<inline>",
                           python_version=(2, 7, 6))
     a = ast.Lookup("a").type
     self.assertItemsEqual(a, pytd.ClassType("int"))
     self.assertIsNotNone(a.cls)  # verify that the lookup succeeded
Example #11
0
 def test_star_import_in_circular_dep(self):
     stub3_ast = self._import(stub1="""
   from stub2 import Foo
   from typing import Mapping as Mapping
 """,
                              stub2="""
   from stub3 import Mapping
   class Foo: ...
 """,
                              stub3="""
   from stub1 import *
 """)
     self.assertEqual(
         stub3_ast.Lookup("stub3.Foo").type, pytd.ClassType("stub2.Foo"))
     self.assertEqual(
         stub3_ast.Lookup("stub3.Mapping").type,
         pytd.ClassType("typing.Mapping"))
Example #12
0
 def testParsePyTD(self):
   """Test ParsePyTD()."""
   ast = builtins.ParsePyTD("a = ...  # type: int",
                            "<inline>", python_version=self.PYTHON_VERSION,
                            lookup_classes=True)
   a = ast.Lookup("a").type
   self.assertItemsEqual(a, pytd.ClassType("int"))
   self.assertIsNotNone(a.cls)  # verify that the lookup succeeded
Example #13
0
 def _create_call_arg(self, name, t, node):
   if t == pytd.ClassType("object"):
     # As an arg, "object" means: we can use anything for this argument,
     # because everything inherits from object.
     # TODO(kramm): Maybe we should use AnythingType for params without type.
     return self.create_new_unsolvable(node, name)
   else:
     return self.create_pytd_instance(name, t, {}, node)
Example #14
0
 def __init__(self, replace_unknown=False, force=False):
     super(AdjustSelf, self).__init__()
     self.class_types = []  # allow nested classes
     self.force = force
     self.replaced_self_types = (pytd.NamedType("object"),
                                 pytd.ClassType("object"))
     if replace_unknown:
         self.replaced_self_types += (pytd.AnythingType(), )
Example #15
0
    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")
        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 = pytd.ClassType("typing.Callable")
        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))
        self.intorfloatorcomplex = pytd.UnionType(
            (self.int, self.float, self.complex))
        self.int_tuple = pytd.GenericType(self.tuple, (self.int, ))
        self.nothing_tuple = pytd.GenericType(self.tuple, (self.nothing, ))
        self.intorfloat_tuple = pytd.GenericType(self.tuple,
                                                 (self.intorfloat, ))
        self.int_set = pytd.GenericType(self.set, (self.int, ))
        self.intorfloat_set = pytd.GenericType(self.set, (self.intorfloat, ))
        self.unknown_frozenset = pytd.GenericType(self.frozenset,
                                                  (self.anything, ))
        self.float_frozenset = pytd.GenericType(self.frozenset, (self.float, ))
        self.empty_frozenset = pytd.GenericType(self.frozenset,
                                                (self.nothing, ))
        self.int_list = pytd.GenericType(self.list, (self.int, ))
        self.str_list = pytd.GenericType(self.list, (self.str, ))
        self.intorfloat_list = pytd.GenericType(self.list, (self.intorfloat, ))
        self.intorstr_list = pytd.GenericType(self.list, (self.intorstr, ))
        self.anything_list = pytd.GenericType(self.list, (self.anything, ))
        self.nothing_list = pytd.GenericType(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))
Example #16
0
    def setUpClass(cls):
        super().setUpClass()
        # We use class-wide loader to avoid creating a new loader for every test
        # method if not required.
        cls._loader = None

        def t(name):  # pylint: disable=invalid-name
            return pytd.ClassType("builtins." + name)

        cls.bool = t("bool")
        cls.dict = t("dict")
        cls.float = t("float")
        cls.complex = t("complex")
        cls.int = t("int")
        cls.list = t("list")
        cls.none_type = t("NoneType")
        cls.object = t("object")
        cls.set = t("set")
        cls.frozenset = t("frozenset")
        cls.str = t("str")
        cls.bytearray = t("bytearray")
        cls.tuple = t("tuple")
        cls.unicode = t("unicode")
        cls.generator = t("generator")
        cls.function = pytd.ClassType("typing.Callable")
        cls.anything = pytd.AnythingType()
        cls.nothing = pytd.NothingType()
        cls.module = t("module")
        cls.file = t("file")

        # The various union types use pytd_utils.CanonicalOrdering()'s ordering:
        cls.intorstr = pytd.UnionType((cls.int, cls.str))
        cls.strorunicode = pytd.UnionType((cls.str, cls.unicode))
        cls.intorfloat = pytd.UnionType((cls.float, cls.int))
        cls.intorfloatorstr = pytd.UnionType((cls.float, cls.int, cls.str))
        cls.complexorstr = pytd.UnionType((cls.complex, cls.str))
        cls.intorfloatorcomplex = pytd.UnionType(
            (cls.int, cls.float, cls.complex))
        cls.int_tuple = pytd.GenericType(cls.tuple, (cls.int, ))
        cls.nothing_tuple = pytd.TupleType(cls.tuple, ())
        cls.intorfloat_tuple = pytd.GenericType(cls.tuple, (cls.intorfloat, ))
        cls.int_set = pytd.GenericType(cls.set, (cls.int, ))
        cls.intorfloat_set = pytd.GenericType(cls.set, (cls.intorfloat, ))
        cls.unknown_frozenset = pytd.GenericType(cls.frozenset,
                                                 (cls.anything, ))
        cls.float_frozenset = pytd.GenericType(cls.frozenset, (cls.float, ))
        cls.empty_frozenset = pytd.GenericType(cls.frozenset, (cls.nothing, ))
        cls.int_list = pytd.GenericType(cls.list, (cls.int, ))
        cls.str_list = pytd.GenericType(cls.list, (cls.str, ))
        cls.intorfloat_list = pytd.GenericType(cls.list, (cls.intorfloat, ))
        cls.intorstr_list = pytd.GenericType(cls.list, (cls.intorstr, ))
        cls.anything_list = pytd.GenericType(cls.list, (cls.anything, ))
        cls.nothing_list = pytd.GenericType(cls.list, (cls.nothing, ))
        cls.int_int_dict = pytd.GenericType(cls.dict, (cls.int, cls.int))
        cls.int_str_dict = pytd.GenericType(cls.dict, (cls.int, cls.str))
        cls.str_int_dict = pytd.GenericType(cls.dict, (cls.str, cls.int))
        cls.nothing_nothing_dict = pytd.GenericType(cls.dict,
                                                    (cls.nothing, cls.nothing))
Example #17
0
def ExternalOrNamedOrClassType(name, cls):
    """Create Classtype / NamedType / ExternalType."""
    if "." in name:
        module, name = name.rsplit(".", 1)
        return pytd.ExternalType(name, module, cls)
    elif cls is None:
        return pytd.NamedType(name)
    else:
        return pytd.ClassType(name, cls)
Example #18
0
 def _create_call_arg(self, name, t, node):
   if t == pytd.ClassType("__builtin__.object"):
     # As an arg, "object" means: we can use anything for this argument,
     # because everything inherits from object.
     # TODO(kramm): Maybe we should use AnythingType for params without type.
     return self.convert.create_new_unsolvable(node, name)
   else:
     return self.convert.convert_constant(
         name, abstract.AsInstance(t), subst={}, node=self.root_cfg_node)
Example #19
0
  def testAnyReplacement(self):
    class_type_match = pytd.ClassType("match.foo")
    named_type_match = pytd.NamedType("match.bar")
    class_type_no_match = pytd.ClassType("match_no.foo")
    named_type_no_match = pytd.NamedType("match_no.bar")
    generic_type_match = pytd.GenericType(class_type_match, ())
    generic_type_no_match = pytd.GenericType(class_type_no_match, ())

    visitor = visitors.ReplaceModulesWithAny(["match."])
    self.assertEqual(class_type_no_match, class_type_no_match.Visit(visitor))
    self.assertEqual(named_type_no_match, named_type_no_match.Visit(visitor))
    self.assertEqual(generic_type_no_match,
                     generic_type_no_match.Visit(visitor))
    self.assertEqual(pytd.AnythingType,
                     class_type_match.Visit(visitor).__class__)
    self.assertEqual(pytd.AnythingType,
                     named_type_match.Visit(visitor).__class__)
    self.assertEqual(pytd.AnythingType,
                     generic_type_match.Visit(visitor).__class__)
Example #20
0
    def VisitNamedType(self, node):
        """Converts a named type to a class type, to be filled in later.

    Args:
      node: The NamedType. This type only has a name.

    Returns:
      A ClassType. This ClassType will (temporarily) only have a name.
    """
        return pytd.ClassType(node.name)
Example #21
0
 def testVerifyHeterogeneousTuple(self):
   # Error: does not inherit from Generic
   base = pytd.ClassType("tuple")
   base.cls = pytd.Class("tuple", None, (), (), (), (), None, ())
   t1 = pytd.TupleType(base, (pytd.NamedType("str"), pytd.NamedType("float")))
   self.assertRaises(visitors.ContainerError,
                     lambda: t1.Visit(visitors.VerifyContainers()))
   # Error: Generic[str, float]
   gen = pytd.ClassType("typing.Generic")
   gen.cls = pytd.Class("typing.Generic", None, (), (), (), (), None, ())
   t2 = pytd.TupleType(gen, (pytd.NamedType("str"), pytd.NamedType("float")))
   self.assertRaises(visitors.ContainerError,
                     lambda: t2.Visit(visitors.VerifyContainers()))
   # Okay
   param = pytd.TypeParameter("T")
   parent = pytd.GenericType(gen, (param,))
   base.cls = pytd.Class(
       "tuple", None, (parent,), (), (), (), None, (pytd.TemplateItem(param),))
   t3 = pytd.TupleType(base, (pytd.NamedType("str"), pytd.NamedType("float")))
   t3.Visit(visitors.VerifyContainers())
Example #22
0
 def testAddNamePrefixOnClassType(self):
   src = textwrap.dedent("""
       x = ...  # type: y
       class Y: ...
   """)
   tree = self.Parse(src)
   x = tree.Lookup("x")
   x = x.Replace(type=pytd.ClassType("Y"))
   tree = tree.Replace(constants=(x,), name="foo")
   tree = tree.Visit(visitors.AddNamePrefix())
   self.assertEqual("foo.Y", tree.Lookup("foo.x").type.name)
Example #23
0
 def _make_pytd_function(self, params):
     pytd_params = []
     for i, p in enumerate(params):
         p_type = pytd.ClassType(p.name)
         p_type.cls = p
         pytd_params.append(
             pytd.Parameter("_" + str(i), p_type, False, False, None))
     pytd_sig = pytd.Signature(tuple(pytd_params), None, None,
                               pytd.AnythingType(), (), ())
     sig = abstract.PyTDSignature("f", pytd_sig, self._vm)
     return abstract.PyTDFunction("f", (sig, ), pytd.METHOD, self._vm)
Example #24
0
  def testInheritFromBuiltins(self):
    ty = self.Infer("""
      class MyDict(dict):
        def __init__(self):
          dict.__setitem__(self, "abc", "foo")

      def f():
        return NoCaseKeysDict()
    """, deep=False, solve_unknowns=False, show_library_calls=True)
    mydict = ty.Lookup("MyDict")
    self.assertOnlyHasReturnType(ty.Lookup("f"),
                                 pytd.ClassType("MyDict", mydict))
Example #25
0
 def _get_known_types_mapping(self):
     # The mapping includes only the types needed to define a namedtuple.
     builtin_classes = ("dict", "int", "NoneType", "object", "str", "tuple",
                        "type")
     typing_classes = ("Callable", "Iterable", "Sized")
     d = {c: self._get_builtin_classtype(c) for c in builtin_classes}
     for c in typing_classes:
         d["typing." + c] = self._get_typing_classtype(c)
     d["collections.OrderedDict"] = pytd.ClassType(
         "collections.OrderedDict",
         self.collections_ast.Lookup("collections.OrderedDict"))
     return d
Example #26
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)
Example #27
0
  def testInheritFromBuiltins(self):
    with self.Infer("""
      class MyDict(dict):
        def __init__(self):
          dict.__setitem__(self, "abc", "foo")

      def f():
        return NoCaseKeysDict()
    """, deep=False, solve_unknowns=False, extract_locals=False) as ty:
      mydict = ty.Lookup("MyDict")
      self.assertOnlyHasReturnType(ty.Lookup("f"),
                                   pytd.ClassType("MyDict", mydict))
Example #28
0
  def testLookup(self):
    with self.Infer("""
      class Cloneable(object):
          def __init__(self):
            pass

          def clone(self):
              return Cloneable()
      Cloneable().clone()
    """, deep=False, solve_unknowns=False, extract_locals=False) as ty:
      cls = ty.Lookup("Cloneable")
      method = cls.Lookup("clone")
      self.assertOnlyHasReturnType(method, pytd.ClassType("Cloneable", cls))
Example #29
0
  def testLookup(self):
    ty = self.Infer("""
      class Cloneable(object):
          def __init__(self):
            pass

          def clone(self):
              return Cloneable()
      Cloneable().clone()
    """, deep=False, show_library_calls=True)
    cls = ty.Lookup("Cloneable")
    method = cls.Lookup("clone")
    self.assertOnlyHasReturnType(method, pytd.ClassType("Cloneable", cls))
Example #30
0
 def _make_pytd_function(self, params, name="f"):
   pytd_params = []
   for i, p in enumerate(params):
     p_type = pytd.ClassType(p.name)
     p_type.cls = p
     pytd_params.append(
         pytd.Parameter(function.argname(i), p_type,
                        pytd.ParameterKind.REGULAR, False, None))
   pytd_sig = pytd.Signature(
       tuple(pytd_params), None, None, pytd.AnythingType(), (), ())
   sig = abstract.PyTDSignature(name, pytd_sig, self._ctx)
   return abstract.PyTDFunction(name, (sig,), pytd.MethodKind.METHOD,
                                self._ctx)