Example #1
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:
                 cls = ast.Lookup(late_type.name)
             except KeyError:
                 if "__getattr__" not in ast:
                     log.warning("Couldn't resolve %s", late_type.name)
                 t = pytd.AnythingType()
             else:
                 t = pytd.ToType(cls, allow_functions=True)
         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 #2
0
def convert_string_type_list(types_as_string,
                             unknown,
                             mapping,
                             global_lookup,
                             depth=0):
    """Like convert_string_type, but operate on a list."""
    if not types_as_string or booleq.Solver.ANY_VALUE in types_as_string:
        # If we didn't find a solution for a type (the list of matches is empty)
        # then report it as "?", not as "nothing", because the latter is confusing.
        return pytd.AnythingType()
    return pytd_utils.JoinTypes(
        convert_string_type(type_as_string, unknown, mapping, global_lookup,
                            depth) for type_as_string in types_as_string)
Example #3
0
 def testLookupConstant(self):
   src1 = textwrap.dedent("""
     Foo = ...  # type: type
   """)
   src2 = textwrap.dedent("""
     class Bar(object):
       bar = ...  # type: foo.Foo
   """)
   ast1 = self.Parse(src1, name="foo")
   ast2 = self.Parse(src2, name="bar")
   ast2 = ast2.Visit(visitors.LookupExternalTypes({"foo": ast1, "bar": ast2}))
   self.assertEqual(ast2.Lookup("bar.Bar").constants[0],
                    pytd.Constant(name="bar", type=pytd.AnythingType()))
Example #4
0
 def _function_call_to_return_type(self, node, v, seen_return, num_returns):
     """Get a function call's pytd return type."""
     if v.signature.has_return_annotation:
         ret = v.signature.annotations["return"].get_instance_type(node)
     else:
         ret = seen_return.data.to_type(node)
         if isinstance(ret, pytd.NothingType) and num_returns == 1:
             if isinstance(seen_return.data, abstract.Empty):
                 ret = pytd.AnythingType()
             else:
                 assert isinstance(seen_return.data,
                                   typing_overlay.NoReturn)
     return ret
Example #5
0
    def to_pytd(self) -> pytd.Parameter:
        """Return a pytd.Parameter object for a normal argument."""
        if self.default is not None:
            default_type = self.default
            if self.type is None and default_type != pytd.NamedType(
                    "NoneType"):
                self.type = default_type
        if self.type is None:
            self.type = pytd.AnythingType()

        optional = self.default is not None
        return pytd.Parameter(self.name, self.type, self.kwonly, optional,
                              None)
Example #6
0
  def _namedtuple_init(self):
    """Build an __init__ method for a namedtuple.

    Builds a dummy __init__ that accepts any arguments. Needed because our
    model of __builtin__.tuple uses __init__.

    Returns:
      A _NameAndSig object for an __init__ method.
    """
    args = [(name, pytd.AnythingType(), None)
            for name in ("self", "*args", "**kwargs")]
    ret = pytd.NamedType("NoneType")
    return self.new_function((), "__init__", args, ret, ())
Example #7
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)
Example #8
0
def merge_method_signatures(
        signatures: List[NameAndSig]) -> List[pytd.Function]:
    """Group the signatures by name, turning each group into a function."""
    name_to_signatures = collections.OrderedDict()
    name_to_decorator = {}
    name_to_is_abstract = {}
    name_to_is_coroutine = {}
    for sig in signatures:
        if sig.name not in name_to_signatures:
            name_to_signatures[sig.name] = []
            name_to_decorator[sig.name] = sig.decorator
        old_decorator = name_to_decorator[sig.name]
        check = _check_decorator_overload(sig.name, old_decorator,
                                          sig.decorator)
        if check == _MERGE:
            name_to_signatures[sig.name].append(sig.signature)
        elif check == _REPLACE:
            name_to_signatures[sig.name] = [sig.signature]
            name_to_decorator[sig.name] = sig.decorator
        _add_flag_overload(name_to_is_abstract, sig.name, sig.is_abstract,
                           "abstractmethod")
        _add_flag_overload(name_to_is_coroutine, sig.name, sig.is_coroutine,
                           "coroutine")
    methods = []
    for name, sigs in name_to_signatures.items():
        decorator = name_to_decorator[name]
        is_abstract = name_to_is_abstract[name]
        is_coroutine = name_to_is_coroutine[name]
        if name == "__new__" or decorator == "staticmethod":
            kind = pytd.STATICMETHOD
        elif name == "__init_subclass__" or decorator == "classmethod":
            kind = pytd.CLASSMETHOD
        elif _is_property(name, decorator, sigs[0]):
            kind = pytd.PROPERTY
            # If we have only setters and/or deleters, replace them with a single
            # method foo(...) -> Any, so that we infer a constant `foo: Any` even if
            # the original method signatures are all `foo(...) -> None`. (If we have a
            # getter we use its return type, but in the absence of a getter we want to
            # fall back on Any since we cannot say anything about what the setter sets
            # the type of foo to.)
            if decorator.endswith(".setter") or decorator.endswith(".deleter"):
                sigs = [sigs[0].Replace(return_type=pytd.AnythingType())]
        else:
            kind = pytd.METHOD
        flags = 0
        if is_abstract:
            flags |= pytd.Function.IS_ABSTRACT
        if is_coroutine:
            flags |= pytd.Function.IS_COROUTINE
        methods.append(pytd.Function(name, tuple(sigs), kind, flags))
    return methods
Example #9
0
 def _parameterized_type(self, base_type, parameters):
   """Return a parameterized type."""
   if self._is_any(base_type):
     return pytd.AnythingType()
   elif len(parameters) == 2 and parameters[-1] is self.ELLIPSIS and (
       not self._is_callable_base_type(base_type)):
     element_type = parameters[0]
     if element_type is self.ELLIPSIS:
       raise ParseError("[..., ...] not supported")
     return pytd.GenericType(base_type=base_type,
                             parameters=(element_type,))
   else:
     parameters = tuple(pytd.AnythingType() if p is self.ELLIPSIS else p
                        for p in parameters)
     if self._is_tuple_base_type(base_type):
       return self._heterogeneous_tuple(base_type, parameters)
     elif (self._is_callable_base_type(base_type) and
           self._is_heterogeneous_tuple(parameters[0])):
       if len(parameters) > 2:
         raise ParseError(
             "Expected 2 parameters to Callable, got %d" % len(parameters))
       if len(parameters) == 1:
         # We're usually happy to treat omitted parameters as "Any", but we
         # need a return type for CallableType, or we wouldn't know whether the
         # last parameter is an argument or return type.
         parameters += (pytd.AnythingType(),)
       if self._is_empty_tuple(parameters[0]):
         parameters = parameters[1:]
       else:
         parameters = parameters[0].parameters + parameters[1:]
       return pytd.CallableType(base_type=base_type, parameters=parameters)
     else:
       assert parameters
       if (self._is_callable_base_type(base_type) and
           not self._is_any(parameters[0])):
         raise ParseError(
             "First argument to Callable must be a list of argument types")
       return pytd.GenericType(base_type=base_type, parameters=parameters)
Example #10
0
 def _value_to_parameter_types(self, node, v, instance, template, seen, view):
   """Get PyTD types for the parameters of an instance of an abstract value."""
   if isinstance(v, abstract.CallableClass):
     assert template == (abstract_utils.ARGS, abstract_utils.RET), template
     template = list(moves.range(v.num_args)) + [template[1]]
   if self._is_tuple(v, instance):
     if isinstance(v, abstract.TupleClass):
       new_template = range(v.tuple_length)
     else:
       new_template = range(instance.tuple_length)
     if template:
       assert len(template) == 1 and template[0] == abstract_utils.T, template
     else:
       # We have a recursive type. By erasing the instance and value
       # information, we'll return Any for all of the tuple elements.
       v = instance = None
     template = new_template
   if instance is None and isinstance(v, abstract.ParameterizedClass):
     return [self.value_instance_to_pytd_type(
         node, v.get_formal_type_parameter(t), None, seen, view)
             for t in template]
   elif isinstance(instance, abstract.SimpleAbstractValue):
     type_arguments = []
     for t in template:
       if isinstance(instance, abstract.Tuple):
         param_values = self._get_values(node, instance.pyval[t], view)
       elif instance.has_instance_type_parameter(t):
         param_values = self._get_values(
             node, instance.get_instance_type_parameter(t), view)
       elif isinstance(v, abstract.CallableClass):
         param_values = v.get_formal_type_parameter(t).instantiate(
             node or self.vm.root_cfg_node).data
       else:
         param_values = [self.vm.convert.unsolvable]
       if (param_values == [self.vm.convert.unsolvable] and
           isinstance(v, abstract.ParameterizedClass) and
           not self.vm.annotations_util.get_type_parameters(
               v.get_formal_type_parameter(t))):
         # When the instance's parameter value is unsolvable, we can get a
         # more precise type from the class. Note that we need to be careful
         # not to introduce unbound type parameters.
         arg = self.value_instance_to_pytd_type(
             node, v.get_formal_type_parameter(t), None, seen, view)
       else:
         arg = pytd_utils.JoinTypes(self.value_to_pytd_type(
             node, p, seen, view) for p in param_values)
       type_arguments.append(arg)
     return type_arguments
   else:
     return [pytd.AnythingType() for _ in template]
Example #11
0
 def test_signature_annotations(self):
     # def f(self: Any, *args: Any)
     self_param = pytd.Parameter("self", pytd.AnythingType(), False, False,
                                 None)
     # Imitate the parser's conversion of '*args: Any' to '*args: Tuple[Any]'.
     tup = pytd.ClassType("__builtin__.tuple")
     tup.cls = self._vm.convert.tuple_type.pytd_cls
     any_tuple = pytd.GenericType(tup, (pytd.AnythingType(), ))
     args_param = pytd.Parameter("args", any_tuple, False, True, None)
     sig = function.Signature.from_pytd(
         self._vm, "f",
         pytd.Signature((self_param, ), args_param, None,
                        pytd.AnythingType(), (), ()))
     self.assertEqual(repr(sig),
                      "def f(self: Any, *args: Tuple[Any, ...]) -> Any")
     self.assertIs(sig.annotations["self"], self._vm.convert.unsolvable)
     args_type = sig.annotations["args"]
     self.assertIsInstance(args_type, abstract.ParameterizedClass)
     self.assertIs(args_type.base_cls, self._vm.convert.tuple_type)
     self.assertListEqual(args_type.type_parameters.items(),
                          [(abstract.T, self._vm.convert.unsolvable)])
     self.assertIs(sig.drop_first_parameter().annotations["args"],
                   args_type)
Example #12
0
def _normal_param(name, param_type, default, kwonly):
  """Return a pytd.Parameter object for a normal argument."""
  if default is not None:
    default_type = _type_for_default(default)
    if default_type == pytd.NamedType("NoneType"):
      if param_type is not None:
        param_type = pytd.UnionType((param_type, default_type))
    elif param_type is None:
      param_type = default_type
  if param_type is None:
    param_type = pytd.AnythingType()

  optional = default is not None
  return pytd.Parameter(name, param_type, kwonly, optional, None)
Example #13
0
 def testPython3Builtins(self):
   # Test that we read python3 builtins from builtin.pytd if we pass a (3, 6)
   # version to the loader.
   with utils.Tempdir() as d:
     d.create_file("a.pyi", """\
         from typing import AsyncGenerator
         class A(AsyncGenerator[str]): ...""")
     loader = load_pytd.Loader("base",
                               python_version=self.PYTHON_VERSION,
                               pythonpath=[d.path])
     a = loader.import_name("a")
     cls = a.Lookup("a.A")
     # New python3 builtins are currently aliases for Any.
     self.assertIn(pytd.AnythingType(), cls.parents)
Example #14
0
 def pytd_for_types(self, defs):
   data = []
   pytd_convert = self.convert.pytd_convert
   annots = abstract_utils.get_annotations_dict(defs)
   for name, t in pytd_convert.uninitialized_annotations_to_instance_types(
       self.exitpoint, annots, defs):
     data.append(pytd.Constant(name, t))
   for name, var in defs.items():
     if name in output.TOP_LEVEL_IGNORE or self._is_builtin(name, var.data):
       continue
     options = var.FilteredData(self.exitpoint, strict=False)
     if (len(options) > 1 and
         not all(isinstance(o, abstract.FUNCTION_TYPES) for o in options)):
       # It's ambiguous whether this is a type, a function or something
       # else, so encode it as a constant.
       combined_types = pytd_utils.JoinTypes(t.to_type(self.exitpoint)
                                             for t in options)
       data.append(pytd.Constant(name, combined_types))
     elif options:
       for option in options:
         try:
           d = option.to_pytd_def(self.exitpoint, name)  # Deep definition
         except NotImplementedError:
           d = option.to_type(self.exitpoint)  # Type only
           if isinstance(d, pytd.NothingType):
             if isinstance(option, abstract.Empty):
               d = pytd.AnythingType()
             else:
               assert isinstance(option, typing_overlay.NoReturn)
         if isinstance(d, pytd.Type) and not isinstance(d, pytd.TypeParameter):
           data.append(pytd.Constant(name, d))
         else:
           data.append(d)
     else:
       log.error("No visible options for %s", name)
       data.append(pytd.Constant(name, pytd.AnythingType()))
   return pytd_utils.WrapTypeDeclUnit("inferred", data)
Example #15
0
 def _function_to_def(self, node, v, function_name):
   """Convert an InterpreterFunction to a PyTD definition."""
   signatures = []
   combinations = tuple(v.get_call_combinations())
   if not combinations:
     # Fallback: Generate a PyTD signature only from the definition of the
     # method, not the way it's being  used.
     param = v.vm.convert.primitive_class_instances[object].to_variable(node)
     ret = v.vm.convert.create_new_unsolvable(node)
     combinations = ((node, collections.defaultdict(lambda: param.bindings[0]),
                      ret.bindings[0]),)
   for node_after, combination, return_value in combinations:
     params = []
     for i, (name, kwonly, optional) in enumerate(v.get_parameters()):
       if i < v.nonstararg_count and name in v.signature.annotations:
         t = v.signature.annotations[name].get_instance_type(node_after)
       else:
         t = combination[name].data.to_type(node_after)
       # Python uses ".0" etc. for the names of parameters that are tuples,
       # like e.g. in: "def f((x,  y), z)".
       params.append(
           pytd.Parameter(name.replace(".", "_"), t, kwonly, optional, None))
     if "return" in v.signature.annotations:
       ret = v.signature.annotations["return"].get_instance_type(node_after)
     else:
       ret = return_value.data.to_type(node_after)
     if isinstance(ret, pytd.NothingType) and len(combinations) == 1:
       assert isinstance(return_value.data, abstract.Empty)
       ret = pytd.AnythingType()
     if v.has_varargs():
       starargs = pytd.Parameter(v.signature.varargs_name,
                                 pytd.NamedType("__builtin__.tuple"),
                                 False, True, None)
     else:
       starargs = None
     if v.has_kwargs():
       starstarargs = pytd.Parameter(v.signature.kwargs_name,
                                     pytd.NamedType("__builtin__.dict"),
                                     False, True, None)
     else:
       starstarargs = None
     signatures.append(pytd.Signature(
         params=tuple(params),
         starargs=starargs,
         starstarargs=starstarargs,
         return_type=ret,
         exceptions=(),  # TODO(kramm): record exceptions
         template=()))
   return pytd.Function(function_name, tuple(signatures), pytd.METHOD)
Example #16
0
  def _class_to_def(self, node, v, class_name):
    """Convert an InterpreterClass to a PyTD definition."""
    methods = {}
    constants = collections.defaultdict(pytd_utils.TypeBuilder)

    # class-level attributes
    for name, member in v.members.items():
      if name not in CLASS_LEVEL_IGNORE:
        for value in member.FilteredData(v.vm.exitpoint):
          if isinstance(value, abstract.Function):
            val = self.value_to_pytd_def(node, value, name)
            if isinstance(val, pytd.Function):
              methods[name] = val
            elif isinstance(v, pytd.TYPE):
              constants[name].add_type(val)
            else:
              raise AssertionError(str(type(val)))
          else:
            constants[name].add_type(value.to_type(node))

    # instance-level attributes
    for instance in v.instances:
      for name, member in instance.members.items():
        if name not in CLASS_LEVEL_IGNORE:
          for value in member.FilteredData(v.vm.exitpoint):
            constants[name].add_type(value.to_type(node))

    for name in list(methods):
      if name in constants:
        # If something is both a constant and a method, it means that the class
        # is, at some point, overwriting its own methods with an attribute.
        del methods[name]
        constants[name].add_type(pytd.AnythingType())

    bases = [pytd_utils.JoinTypes(b.get_instance_type(node)
                                  for b in basevar.data)
             for basevar in v.bases()
             if basevar is not v.vm.convert.oldstyleclass_type]
    constants = [pytd.Constant(name, builder.build())
                 for name, builder in constants.items() if builder]
    metaclass = v.metaclass(node)
    if metaclass is not None:
      metaclass = metaclass.get_instance_type(node)
    return pytd.Class(name=class_name,
                      metaclass=metaclass,
                      parents=tuple(bases),
                      methods=tuple(methods.values()),
                      constants=tuple(constants),
                      template=())
Example #17
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:
     ast = self.ctx.loader.import_name(late_type.name)
     if ast:
       t = pytd.Module(name=late_type.name, module_name=late_type.name)
     else:
       ast, attr_name = self._load_late_type_module(late_type)
       if ast is None:
         log.error(
             "During dependency resolution, couldn't resolve late type %r",
             late_type.name)
         t = pytd.AnythingType()
       else:
         try:
           cls = pytd.LookupItemRecursive(ast, attr_name)
         except KeyError:
           if "__getattr__" not in ast:
             log.warning("Couldn't resolve %s", late_type.name)
           t = pytd.AnythingType()
         else:
           t = pytd.ToType(cls, allow_functions=True)
     self._resolved_late_types[late_type.name] = t
   return self._resolved_late_types[late_type.name]
Example #18
0
 def _function_to_return_types(self, node, fvar):
   """Convert a function variable to a list of PyTD return types."""
   options = fvar.FilteredData(self.vm.exitpoint, strict=False)
   if not all(isinstance(o, abstract.Function) for o in options):
     return [pytd.AnythingType()]
   types = []
   for val in options:
     if isinstance(val, abstract.InterpreterFunction):
       combinations = val.get_call_combinations(node)
       for sig, node_after, _, return_value in combinations:
         types.append(self._function_call_to_return_type(
             sig, node_after, val, return_value, len(combinations)))
     elif isinstance(val, abstract.PyTDFunction):
       types.extend(sig.pytd_sig.return_type for sig in val.signatures)
     else:
       types.append(pytd.AnythingType())
   safe_types = []  # types without type parameters
   for t in types:
     collector = visitors.CollectTypeParameters()
     t.Visit(collector)
     t = t.Visit(visitors.ReplaceTypeParameters(
         {p: p.upper_value for p in collector.params}))
     safe_types.append(t)
   return safe_types
Example #19
0
 def _Convert(self, t):
   module, name = self._GetModuleAndName(t)
   if not module and name == "None":
     # PEP 484 allows "None" as an abbreviation of "NoneType".
     return pytd.NamedType("NoneType")
   elif self._IsTyping(module):
     if name in PEP484_CAPITALIZED:
       return pytd.NamedType(name.lower())  # "typing.List" -> "list" etc.
     elif name == "Any":
       return pytd.AnythingType()
     else:
       # IO, Callable, etc. (I.e., names in typing we leave alone)
       return t
   else:
     return t
Example #20
0
 def _get_parameters(self, t1, t2):
     if isinstance(t1, pytd.TupleType) and isinstance(t2, pytd.TupleType):
         # No change needed; the parameters will be compared element-wise.
         return t1.parameters, t2.parameters
     elif isinstance(t2, pytd.TupleType):
         # Since we call _get_parameters after confirming that t1 and t2 have
         # compatible base types, t1 is a homogeneous tuple here.
         return (t1.element_type, ) * len(t2.parameters), t2.parameters
     elif isinstance(t1, pytd.TupleType):
         return (pytd.UnionType(type_list=t1.parameters), ), t2.parameters
     elif (isinstance(t1, pytd.CallableType)
           and isinstance(t2, pytd.CallableType)):
         # Flip the arguments, since argument types are contravariant.
         return t2.args + (t1.ret, ), t1.args + (t2.ret, )
     elif (t1.base_type.cls.name == "__builtin__.type"
           and t2.base_type.cls.name == "typing.Callable"):
         # We'll only check the return type, since getting the argument types for
         # initializing a class is tricky.
         return t1.parameters, (t2.parameters[-1], )
     elif (t1.base_type.cls.name == "typing.Callable"
           and t2.base_type.cls.name == "__builtin__.type"):
         return (t1.parameters[-1], ), t2.parameters
     elif isinstance(t1, pytd.CallableType):
         # We're matching against GenericType(Callable, (Any, _RET)), so we don't
         # need the argument types.
         return (pytd.AnythingType(), t1.ret), t2.parameters
     elif isinstance(t2, pytd.CallableType):
         return t1.parameters, (pytd.AnythingType(), t2.ret)
     else:
         num_extra_params = len(t1.parameters) - len(t2.parameters)
         # Matching, e.g., Dict[str, int] against Iterable[K] is legitimate.
         assert num_extra_params >= 0, (t1.base_type.cls.name,
                                        t2.base_type.cls.name)
         t2_parameters = t2.parameters + (
             pytd.AnythingType(), ) * num_extra_params
         return t1.parameters, t2_parameters
Example #21
0
  def testAliasPrinting(self):
    a = pytd.Alias("MyList", pytd.GenericType(
        pytd.NamedType("typing.List"), (pytd.AnythingType(),)))
    ty = pytd.TypeDeclUnit(
        name="test",
        constants=(),
        type_params=(),
        classes=(),
        functions=(),
        aliases=(a,))
    expected = textwrap.dedent("""
      from typing import Any, List

      MyList = List[Any]""")
    self.assertMultiLineEqual(expected.strip(), pytd.Print(ty).strip())
Example #22
0
def DummyMethod(name, *params):
    """Create a simple method using only "Any"s as types.

  Arguments:
    name: The name of the method
    *params: The parameter names.
  Returns:
    A pytd.Function.
  """
    sig = pytd.Signature(tuple(
        pytd.Parameter(param,
                       type=pytd.AnythingType(),
                       kwonly=False,
                       optional=False,
                       mutated_type=None) for param in params),
                         starargs=None,
                         starstarargs=None,
                         return_type=pytd.AnythingType(),
                         exceptions=(),
                         template=())
    return pytd.Function(name=name,
                         signatures=(sig, ),
                         kind=pytd.METHOD,
                         flags=0)
Example #23
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)
Example #24
0
  def _make_init(self) -> function.NameAndSig:
    """Build an __init__ method for a namedtuple.

    Builds a dummy __init__ that accepts any arguments. Needed because our
    model of builtins.tuple uses __init__.

    Returns:
      A function.NameAndSig object for an __init__ method.
    """
    self_arg = function.Param("self", pytd.AnythingType()).to_pytd()
    ret = pytd.NamedType("NoneType")
    sig = pytd.Signature(params=(self_arg,), return_type=ret,
                         starargs=function.pytd_default_star_param(),
                         starstarargs=function.pytd_default_starstar_param(),
                         exceptions=(), template=())
    return function.NameAndSig("__init__", sig)
Example #25
0
 def _value_to_parameter_types(self, node, v, instance, template, seen,
                               view):
     """Get PyTD types for the parameters of an instance of an abstract value."""
     if isinstance(v, abstract.Callable):
         assert template == (abstract.ARGS, abstract.RET), template
         template = range(v.num_args) + [template[1]]
     if self._is_tuple(v, instance):
         if isinstance(v, abstract.TupleClass):
             new_template = range(v.tuple_length)
         else:
             new_template = range(instance.tuple_length)
         if template:
             assert len(
                 template) == 1 and template[0] == abstract.T, template
         else:
             # We have a recursive type. By erasing the instance and value
             # information, we'll return Any for all of the tuple elements.
             v = instance = None
         template = new_template
     if instance is None and isinstance(v, abstract.ParameterizedClass):
         return [
             self.value_instance_to_pytd_type(node, v.type_parameters[t],
                                              None, seen, view)
             for t in template
         ]
     elif isinstance(instance, abstract.SimpleAbstractValue):
         type_arguments = []
         for t in template:
             if isinstance(instance, abstract.Tuple):
                 param_values = self._get_values(node, instance.pyval[t],
                                                 view)
             elif t in instance.type_parameters:
                 param_values = self._get_values(
                     node, instance.type_parameters[t], view)
             elif isinstance(v, abstract.Callable):
                 param_values = v.type_parameters[t].instantiate(
                     node or v.vm.root_cfg_node).data
             else:
                 param_values = [v.vm.convert.unsolvable]
             type_arguments.append(
                 pytd_utils.JoinTypes(
                     self.value_to_pytd_type(node, p, seen, view)
                     for p in param_values))
         return type_arguments
     else:
         return [pytd.AnythingType() for _ in template]
Example #26
0
 def _FormatContainerContents(self, node):
     """Print out the last type parameter of a container. Used for *args/**kw."""
     assert isinstance(node, pytd.Parameter)
     if isinstance(node.type, pytd.GenericType):
         container_name = node.type.base_type.name.rpartition(".")[2]
         assert container_name in ("tuple", "dict")
         self._typing_import_counts[container_name.capitalize()] -= 1
         # If the type is "Any", e.g. `**kwargs: Any`, decrement Any to avoid an
         # extraneous import of typing.Any. Any was visited before this function
         # transformed **kwargs, so it was incremented at least once already.
         if isinstance(node.type.parameters[-1], pytd.AnythingType):
             self._typing_import_counts["Any"] -= 1
         return node.Replace(type=node.type.parameters[-1],
                             optional=False).Visit(PrintVisitor())
     else:
         return node.Replace(type=pytd.AnythingType(),
                             optional=False).Visit(PrintVisitor())
Example #27
0
 def match_Function_against_Class(self, f1, cls2, subst, cache):
     cls2_methods = cache.get(id(cls2))
     if cls2_methods is None:
         cls2_methods = cache[id(cls2)] = {f.name: f for f in cls2.methods}
     if f1.name not in cls2_methods:
         # The class itself doesn't have this method, but base classes might.
         # TODO(kramm): This should do MRO order, not depth-first.
         for base in cls2.parents:
             if isinstance(base, pytd.AnythingType):
                 # AnythingType can contain any method. However, that would mean that
                 # a class that inherits from AnythingType contains any method
                 # imaginable, and hence is a match for anything. To prevent the bad
                 # results caused by that, return FALSE here.
                 return booleq.FALSE
             elif isinstance(base, (pytd.ClassType, pytd.GenericType)):
                 if isinstance(base, pytd.ClassType):
                     cls = base.cls
                     values = tuple(pytd.AnythingType()
                                    for _ in cls.template)
                 elif isinstance(base, pytd.TupleType):
                     cls = base.base_type.cls
                     values = (pytd.UnionType(type_list=base.parameters), )
                 else:
                     cls = base.base_type.cls
                     values = base.parameters
                 if values:
                     subst = subst.copy()
                     for param, value in zip(cls.template, values):
                         subst[param.type_param] = value
                 implication = self.match_Function_against_Class(
                     f1, cls, subst, cache)
                 if implication is not booleq.FALSE:
                     return implication
             else:
                 # Funky types like UnionType are hard to match against (and shouldn't
                 # appear as a base class) so we treat them as catch-all.
                 log.warning("Assuming that %s has method %s",
                             pytd_utils.Print(base), f1.name)
                 return booleq.TRUE
         return booleq.FALSE
     else:
         f2 = cls2_methods[f1.name]
         return self.match_Function_against_Function(f1,
                                                     f2,
                                                     subst,
                                                     skip_self=True)
Example #28
0
 def p_type_homogeneous(self, p):
     """type : named_or_external_type LBRACKET parameters RBRACKET"""
     _, base_type, _, parameters, _ = p
     if p[1] == pytd.NamedType('Union'):
         p[0] = pytd.UnionType(parameters)
     elif p[1] == pytd.NamedType('Optional'):
         p[0] = pytd.UnionType(parameters[0], pytd.NamedType('None'))
     elif len(parameters) == 2 and parameters[-1] is Ellipsis:
         element_type, _ = parameters
         if element_type is Ellipsis:
             make_syntax_error(self, '[..., ...] not supported', p)
         p[0] = pytd.HomogeneousContainerType(base_type=base_type,
                                              parameters=(element_type, ))
     else:
         parameters = tuple(pytd.AnythingType() if p is Ellipsis else p
                            for p in parameters)
         p[0] = pytd.GenericType(base_type=base_type, parameters=parameters)
Example #29
0
 def VisitNamedType(self, node):
     name = node.name
     for lookup in self._lookup_list:
         try:
             cls = lookup.Lookup(name)
             if isinstance(cls, pytd.Class):
                 return node
         except KeyError:
             pass
     if "." in node.name:
         logging.warning("Marking %s as external", name)
         module_name, base_name = name.rsplit(".", 1)
         return pytd.ExternalType(base_name, module_name)
     else:
         if (self._do_not_log_prefix is None
                 or not name.startswith(self._do_not_log_prefix)):
             logging.error("Setting %s to ?", name)
         return pytd.AnythingType()
Example #30
0
 def new_new_type(self, name, typ):
     """Returns a type for a NewType."""
     args = [("self", pytd.AnythingType()), ("val", typ)]
     ret = pytd.NamedType("NoneType")
     methods = function.merge_method_signatures(
         [function.NameAndSig.make("__init__", args, ret)])
     cls_name = escape.pack_newtype_base_class(
         name, len(self.generated_classes[name]))
     cls = pytd.Class(name=cls_name,
                      metaclass=None,
                      parents=(typ, ),
                      methods=tuple(methods),
                      constants=(),
                      decorators=(),
                      classes=(),
                      slots=None,
                      template=())
     self.generated_classes[name].append(cls)
     return pytd.NamedType(cls_name)