Beispiel #1
0
    def EnterSignature(self, signature):
        """Parse a signature, and update self.operators.

    This will add the reverse of operators like __radd__ to self.operators for
    later processing by PreprocessReverseOperatorsVisitor.

    Args:
      signature: A pytd.Signature

    Returns:
      False, to indicate that we don't want this visitor to descend into the
      subtree of the signature.
    """
        if self.unreversed_name:
            assert len(signature.params) == 2
            left, right = signature.params[0].type, signature.params[1].type
            if isinstance(left, pytd.ClassType) and isinstance(
                    right, pytd.ClassType):
                if self._ShouldReplace(right.cls, left.cls,
                                       self.unreversed_name,
                                       self.function_name):
                    self.operators[right.cls][self.unreversed_name].append(
                        signature.Replace(
                            params=(pytd.Parameter("self", right),
                                    pytd.Parameter("other", left))))
                else:
                    logging.warn("Ignoring %s on %s: %s has %s",
                                 self.function_name, left.name, right.name,
                                 self.unreversed_name)
            else:
                logging.warn("Unsupported %s operator on %s",
                             self.function_name,
                             type(right).__name__)
        return False  # don't bother descending into this signature
Beispiel #2
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)
Beispiel #3
0
    def to_structural_def(self, node, class_name):
        """Convert this Unknown to a pytd.Class."""
        self_param = (pytd.Parameter("self", pytd.AnythingType(),
                                     pytd.ParameterKind.REGULAR, False,
                                     None), )
        starargs = None
        starstarargs = None

        def _make_sig(args, ret):
            return pytd.Signature(self_param + self._make_params(node, args),
                                  starargs,
                                  starstarargs,
                                  return_type=Unknown._to_pytd(node, ret),
                                  exceptions=(),
                                  template=())

        calls = tuple(
            pytd_utils.OrderedSet(
                _make_sig(args, ret) for args, _, ret in self._calls))
        if calls:
            methods = (pytd.Function("__call__", calls,
                                     pytd.MethodKind.METHOD), )
        else:
            methods = ()
        return pytd.Class(name=class_name,
                          metaclass=None,
                          bases=(pytd.NamedType("builtins.object"), ),
                          methods=methods,
                          constants=tuple(
                              pytd.Constant(name, Unknown._to_pytd(node, c))
                              for name, c in self.members.items()),
                          classes=(),
                          decorators=(),
                          slots=None,
                          template=())
Beispiel #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"))))),
                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"))
Beispiel #5
0
    def _simple_func_to_def(self, node, v, name):
        """Convert a SimpleFunction to a PyTD definition."""
        sig = v.signature

        def get_parameter(p, kind):
            return pytd.Parameter(p,
                                  sig.annotations[p].get_instance_type(node),
                                  kind, p in sig.defaults, None)

        posonly = [
            get_parameter(p, pytd.ParameterKind.POSONLY)
            for p in sig.posonly_params
        ]
        params = [
            get_parameter(p, pytd.ParameterKind.REGULAR)
            for p in sig.param_names[sig.posonly_count:]
        ]
        kwonly = [
            get_parameter(p, pytd.ParameterKind.KWONLY)
            for p in sig.kwonly_params
        ]
        if sig.varargs_name:
            star = pytd.Parameter(
                sig.varargs_name,
                sig.annotations[sig.varargs_name].get_instance_type(node),
                pytd.ParameterKind.REGULAR, False, None)
        else:
            star = None
        if sig.kwargs_name:
            starstar = pytd.Parameter(
                sig.kwargs_name,
                sig.annotations[sig.kwargs_name].get_instance_type(node),
                pytd.ParameterKind.REGULAR, False, None)
        else:
            starstar = None
        if sig.has_return_annotation:
            ret_type = sig.annotations["return"].get_instance_type(node)
        else:
            ret_type = pytd.NamedType("builtins.NoneType")
        pytd_sig = pytd.Signature(params=tuple(posonly + params + kwonly),
                                  starargs=star,
                                  starstarargs=starstar,
                                  return_type=ret_type,
                                  exceptions=(),
                                  template=())
        return pytd.Function(name, (pytd_sig, ), pytd.MethodKind.METHOD)
Beispiel #6
0
 def _function_call_combination_to_signature(self, func, call_combination,
                                             num_combinations):
     node_after, combination, return_value = call_combination
     params = []
     for i, (name, kind, optional) in enumerate(func.get_parameters()):
         if i < func.nonstararg_count and name in func.signature.annotations:
             t = func.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, kind, optional,
                            None))
     ret = self._function_call_to_return_type(node_after, func,
                                              return_value,
                                              num_combinations)
     if func.has_varargs():
         if func.signature.varargs_name in func.signature.annotations:
             annot = func.signature.annotations[func.signature.varargs_name]
             typ = annot.get_instance_type(node_after)
         else:
             typ = pytd.NamedType("builtins.tuple")
         starargs = pytd.Parameter(func.signature.varargs_name, typ,
                                   pytd.ParameterKind.REGULAR, True, None)
     else:
         starargs = None
     if func.has_kwargs():
         if func.signature.kwargs_name in func.signature.annotations:
             annot = func.signature.annotations[func.signature.kwargs_name]
             typ = annot.get_instance_type(node_after)
         else:
             typ = pytd.NamedType("builtins.dict")
         starstarargs = pytd.Parameter(func.signature.kwargs_name, typ,
                                       pytd.ParameterKind.REGULAR, True,
                                       None)
     else:
         starstarargs = None
     return pytd.Signature(
         params=tuple(params),
         starargs=starargs,
         starstarargs=starstarargs,
         return_type=ret,
         exceptions=(),  # TODO(b/159052087): record exceptions
         template=())
Beispiel #7
0
 def _call_traces_to_function(call_traces, prefix=""):
   funcs = collections.defaultdict(pytd_utils.OrderedSet)
   for funcvar, args, kws, retvar in call_traces:
     if isinstance(funcvar.data, abstract.BoundFunction):
       func = funcvar.data.underlying.signatures[0]
     else:
       func = funcvar.data.signatures[0]
     arg_names = func.get_parameter_names()
     arg_types = (a.data.to_type()
                  for a in func.get_bound_arguments() + list(args))
     ret = pytd_utils.JoinTypes(t.to_type() for t in retvar.data)
     funcs[funcvar.data.name].add(pytd.Signature(
         tuple(pytd.Parameter(n, t)
               for n, t in zip(arg_names, arg_types)) +
         tuple(pytd.Parameter(name, a.data.to_type())
               for name, a in kws),
         ret, has_optional=False, exceptions=(), template=()))
   functions = []
   for name, signatures in funcs.items():
     functions.append(pytd.Function(prefix + name, tuple(signatures)))
   return functions
Beispiel #8
0
    def VisitParameter(self, p):
        """Adjust all parameters called "self" to have their parent class type.

    But do this only if their original type is unoccupied ("object" or,
    if configured, "?").

    Args:
      p: pytd.Parameter instance.

    Returns:
      Adjusted pytd.Parameter instance.
    """
        if not self.class_types:
            # We're not within a class, so this is not a parameter of a method.
            return p
        if p.name == "self" and (self.force
                                 or p.type in self.replaced_self_types):
            return pytd.Parameter("self", self.class_types[-1])
        else:
            return p