示例#1
0
 def _match_type_against_callback_protocol(
     self, left, other_type, subst, node, view):
   """See https://www.python.org/dev/peps/pep-0544/#callback-protocols."""
   _, method_var = self.vm.attribute_handler.get_attribute(
       node, other_type, "__call__")
   if not method_var or not method_var.data or any(
       not isinstance(v, abstract.Function) for v in method_var.data):
     return None
   new_substs = []
   for expected_method in method_var.data:
     signatures = abstract_utils.get_signatures(expected_method)
     for sig in signatures:
       sig = sig.drop_first_parameter()  # drop `self`
       expected_callable = (
           self.vm.convert.pytd_convert.signature_to_callable(sig))
       new_subst = self._match_type_against_type(
           left, expected_callable, subst, node, view)
       if new_subst is not None:
         # For a set of overloaded signatures, only one needs to match.
         new_substs.append(new_subst)
         break
     else:
       # Every method_var binding must have a matching signature.
       return None
   return self._merge_substs(subst, new_substs)
示例#2
0
  def value_to_pytd_type(self, node, v, seen, view):
    """Get a PyTD type representing this object, as seen at a node.

    Args:
      node: The node from which we want to observe this object.
      v: The object.
      seen: The set of values seen before while computing the type.
      view: A Variable -> binding map.

    Returns:
      A PyTD type.
    """
    if isinstance(v, (abstract.Empty, typing_overlay.NoReturn)):
      return pytd.NothingType()
    elif isinstance(v, abstract.TypeParameterInstance):
      if v.instance.get_instance_type_parameter(v.full_name).bindings:
        # The type parameter was initialized. Set the view to None, since we
        # don't include v.instance in the view.
        return pytd_utils.JoinTypes(
            self.value_to_pytd_type(node, p, seen, None)
            for p in v.instance.get_instance_type_parameter(v.full_name).data)
      elif v.param.constraints:
        return pytd_utils.JoinTypes(
            self.value_instance_to_pytd_type(node, p, None, seen, view)
            for p in v.param.constraints)
      elif v.param.bound:
        return self.value_instance_to_pytd_type(
            node, v.param.bound, None, seen, view)
      else:
        return pytd.AnythingType()
    elif isinstance(v, typing_overlay.TypeVar):
      return pytd.NamedType("__builtin__.type")
    elif isinstance(v, abstract.FUNCTION_TYPES):
      try:
        signatures = abstract_utils.get_signatures(v)
      except NotImplementedError:
        return pytd.NamedType("typing.Callable")
      if len(signatures) == 1:
        val = self.signature_to_callable(signatures[0], self.vm)
        if (not isinstance(v, abstract.PYTD_FUNCTION_TYPES) or
            not self.vm.annotations_util.get_type_parameters(val)):
          # This is a workaround to make sure we don't put unexpected type
          # parameters in call traces.
          return self.value_instance_to_pytd_type(node, val, None, seen, view)
      return pytd.NamedType("typing.Callable")
    elif isinstance(v, (abstract.ClassMethod, abstract.StaticMethod)):
      return self.value_to_pytd_type(node, v.method, seen, view)
    elif isinstance(v, (special_builtins.IsInstance,
                        special_builtins.ClassMethodCallable)):
      return pytd.NamedType("typing.Callable")
    elif isinstance(v, mixin.Class):
      param = self.value_instance_to_pytd_type(node, v, None, seen, view)
      return pytd.GenericType(base_type=pytd.NamedType("__builtin__.type"),
                              parameters=(param,))
    elif isinstance(v, abstract.Module):
      return pytd.NamedType("__builtin__.module")
    elif isinstance(v, abstract.SimpleAbstractValue):
      if v.cls:
        ret = self.value_instance_to_pytd_type(
            node, v.cls, v, seen=seen, view=view)
        ret.Visit(visitors.FillInLocalPointers(
            {"__builtin__": self.vm.loader.builtins}))
        return ret
      else:
        # We don't know this type's __class__, so return AnythingType to
        # indicate that we don't know anything about what this is.
        # This happens e.g. for locals / globals, which are returned from the
        # code in class declarations.
        log.info("Using ? for %s", v.name)
        return pytd.AnythingType()
    elif isinstance(v, abstract.Union):
      return pytd.UnionType(tuple(self.value_to_pytd_type(node, o, seen, view)
                                  for o in v.options))
    elif isinstance(v, special_builtins.SuperInstance):
      return pytd.NamedType("__builtin__.super")
    elif isinstance(v, (abstract.Unsolvable, abstract.TypeParameter)):
      # Arguably, the type of a type parameter is NamedType("typing.TypeVar"),
      # but pytype doesn't know how to handle that, so let's just go with Any.
      return pytd.AnythingType()
    elif isinstance(v, abstract.Unknown):
      return pytd.NamedType(v.class_name)
    elif isinstance(v, abstract.BuildClass):
      return pytd.NamedType("typing.Callable")
    else:
      raise NotImplementedError(v.__class__.__name__)
示例#3
0
  def _match_type_against_type(self, left, other_type, subst, node, view):
    """Checks whether a type is compatible with a (formal) type.

    Args:
      left: A type.
      other_type: A formal type. E.g. mixin.Class or abstract.Union.
      subst: The current type parameter assignment.
      node: The current CFG node.
      view: The current mapping of Variable to Value.
    Returns:
      A new type parameter assignment if the matching succeeded, None otherwise.
    """
    if (isinstance(left, abstract.Empty) and
        isinstance(other_type, abstract.Empty)):
      return subst
    elif isinstance(left, abstract.AMBIGUOUS_OR_EMPTY):
      params = self.vm.annotations_util.get_type_parameters(other_type)
      if isinstance(left, abstract.Empty):
        value = self.vm.convert.empty
      else:
        value = self.vm.convert.unsolvable
      return self._mutate_type_parameters(params, value, subst, node)
    elif isinstance(left, mixin.Class):
      if (other_type.full_name == "builtins.type" and
          isinstance(other_type, abstract.ParameterizedClass)):
        other_type = other_type.get_formal_type_parameter(abstract_utils.T)
        return self._instantiate_and_match(left, other_type, subst, node, view)
      elif (other_type.full_name == "typing.Callable" and
            isinstance(other_type, abstract.ParameterizedClass)):
        # TODO(rechen): Check left's constructor against the callable's params.
        other_type = other_type.get_formal_type_parameter(abstract_utils.RET)
        return self._instantiate_and_match(left, other_type, subst, node, view)
      elif other_type.full_name in [
          "builtins.type", "builtins.object", "typing.Callable",
          "typing.Hashable"]:
        return subst
      elif _is_callback_protocol(other_type):
        return self._match_type_against_callback_protocol(
            left, other_type, subst, node, view)
      elif left.cls:
        return self._match_instance_against_type(
            left, other_type, subst, node, view)
    elif isinstance(left, abstract.Module):
      if other_type.full_name in [
          "builtins.module", "builtins.object", "types.ModuleType",
          "typing.Hashable"]:
        return subst
    elif isinstance(left, abstract.FUNCTION_TYPES):
      if other_type.full_name == "typing.Callable":
        if not isinstance(other_type, abstract.ParameterizedClass):
          # The callable has no parameters, so any function matches it.
          return subst
        if isinstance(left, abstract.NativeFunction):
          # If we could get the class on which 'left' is defined (perhaps by
          # using bound_class?), we could get the argument and return types
          # from the underlying PyTDFunction, but we wouldn't get much value
          # out of that additional matching, since most NativeFunction objects
          # are magic methods like __getitem__ which aren't likely to be passed
          # as function arguments.
          return subst
        signatures = abstract_utils.get_signatures(left)
        for sig in signatures:
          new_subst = self._match_signature_against_callable(
              sig, other_type, subst, node, view)
          if new_subst is not None:
            return new_subst
        return None
      elif _is_callback_protocol(other_type):
        return self._match_type_against_callback_protocol(
            left, other_type, subst, node, view)
      elif left.cls:
        return self._match_type_against_type(
            abstract.Instance(left.cls, self.vm), other_type, subst, node, view)
      else:
        return None
    elif isinstance(left, dataclass_overlay.FieldInstance) and left.default:
      return self._match_all_bindings(
          left.default, other_type, subst, node, view)
    elif isinstance(left, abstract.SimpleValue):
      return self._match_instance_against_type(
          left, other_type, subst, node, view)
    elif isinstance(left, special_builtins.SuperInstance):
      return self._match_class_and_instance_against_type(
          left.super_cls, left.super_obj, other_type, subst, node, view)
    elif isinstance(left, abstract.ClassMethod):
      if other_type.full_name in [
          "builtins.classmethod", "builtins.object"]:
        return subst
      return self._match_type_against_type(
          left.to_bound_function(), other_type, subst, node, view)
    elif isinstance(left, abstract.StaticMethod):
      if other_type.full_name in [
          "builtins.staticmethod", "builtins.object"]:
        return subst
      return self._match_type_against_type(
          left.method, other_type, subst, node, view)
    elif isinstance(left, abstract.Union):
      for o in left.options:
        new_subst = self._match_type_against_type(
            o, other_type, subst, node, view)
        if new_subst is not None:
          return new_subst
    elif isinstance(left, abstract.TypeParameterInstance):
      return self._instantiate_and_match(
          left.param, other_type, subst, node, view)
    else:
      raise NotImplementedError("Matching not implemented for %s against %s" %
                                (type(left), type(other_type)))
示例#4
0
文件: output.py 项目: mic1234/pytype
    def value_to_pytd_type(self, node, v, seen, view):
        """Get a PyTD type representing this object, as seen at a node.

    Args:
      node: The node from which we want to observe this object.
      v: The object.
      seen: The set of values seen before while computing the type.
      view: A Variable -> binding map.

    Returns:
      A PyTD type.
    """
        if isinstance(v, (abstract.Empty, typing_overlay.NoReturn)):
            return pytd.NothingType()
        elif isinstance(v, abstract.TypeParameterInstance):
            if v.module in self._scopes:
                return self._typeparam_to_def(node, v.param, v.param.name)
            elif v.instance.get_instance_type_parameter(v.full_name).bindings:
                # The type parameter was initialized. Set the view to None, since we
                # don't include v.instance in the view.
                return pytd_utils.JoinTypes(
                    self.value_to_pytd_type(node, p, seen, None) for p in
                    v.instance.get_instance_type_parameter(v.full_name).data)
            elif v.param.constraints:
                return pytd_utils.JoinTypes(
                    self.value_instance_to_pytd_type(node, p, None, seen, view)
                    for p in v.param.constraints)
            elif v.param.bound:
                return self.value_instance_to_pytd_type(
                    node, v.param.bound, None, seen, view)
            else:
                return pytd.AnythingType()
        elif isinstance(v, typing_overlay.TypeVar):
            return pytd.NamedType("builtins.type")
        elif isinstance(v, dataclass_overlay.FieldInstance):
            if not v.default:
                return pytd.AnythingType()
            return pytd_utils.JoinTypes(
                self.value_to_pytd_type(node, d, seen, view)
                for d in v.default.data)
        elif isinstance(v, abstract.FUNCTION_TYPES):
            try:
                signatures = abstract_utils.get_signatures(v)
            except NotImplementedError:
                return pytd.NamedType("typing.Callable")
            if len(signatures) == 1:
                val = self.signature_to_callable(signatures[0])
                if not isinstance(
                        v, abstract.PYTD_FUNCTION_TYPES) or not val.formal:
                    # This is a workaround to make sure we don't put unexpected type
                    # parameters in call traces.
                    return self.value_instance_to_pytd_type(
                        node, val, None, seen, view)
            return pytd.NamedType("typing.Callable")
        elif isinstance(v, (abstract.ClassMethod, abstract.StaticMethod)):
            return self.value_to_pytd_type(node, v.method, seen, view)
        elif isinstance(v, (special_builtins.IsInstance,
                            special_builtins.ClassMethodCallable)):
            return pytd.NamedType("typing.Callable")
        elif isinstance(v, class_mixin.Class):
            param = self.value_instance_to_pytd_type(node, v, None, seen, view)
            return pytd.GenericType(base_type=pytd.NamedType("builtins.type"),
                                    parameters=(param, ))
        elif isinstance(v, abstract.Module):
            return pytd.NamedType("builtins.module")
        elif (self._output_mode >= Converter.OutputMode.LITERAL
              and isinstance(v, abstract.ConcreteValue)
              and isinstance(v.pyval, (int, str, bytes))):
            # LITERAL mode is used only for pretty-printing, so we just stringify the
            # inner value rather than properly converting it.
            return pytd.Literal(repr(v.pyval))
        elif isinstance(v, abstract.SimpleValue):
            if v.cls:
                ret = self.value_instance_to_pytd_type(node,
                                                       v.cls,
                                                       v,
                                                       seen=seen,
                                                       view=view)
                ret.Visit(
                    visitors.FillInLocalPointers(
                        {"builtins": self.vm.loader.builtins}))
                return ret
            else:
                # We don't know this type's __class__, so return AnythingType to
                # indicate that we don't know anything about what this is.
                # This happens e.g. for locals / globals, which are returned from the
                # code in class declarations.
                log.info("Using Any for %s", v.name)
                return pytd.AnythingType()
        elif isinstance(v, abstract.Union):
            opts = []
            for o in v.options:
                # NOTE: Guarding printing of type parameters behind _detailed until
                # round-tripping is working properly.
                if self._detailed and isinstance(o, abstract.TypeParameter):
                    opt = self._typeparam_to_def(node, o, o.name)
                else:
                    opt = self.value_to_pytd_type(node, o, seen, view)
                opts.append(opt)
            return pytd.UnionType(tuple(opts))
        elif isinstance(v, special_builtins.SuperInstance):
            return pytd.NamedType("builtins.super")
        elif isinstance(v, abstract.TypeParameter):
            # Arguably, the type of a type parameter is NamedType("typing.TypeVar"),
            # but pytype doesn't know how to handle that, so let's just go with Any
            # unless self._detailed is set.
            if self._detailed:
                return pytd.NamedType("typing.TypeVar")
            else:
                return pytd.AnythingType()
        elif isinstance(v, abstract.Unsolvable):
            return pytd.AnythingType()
        elif isinstance(v, abstract.Unknown):
            return pytd.NamedType(v.class_name)
        elif isinstance(v, abstract.BuildClass):
            return pytd.NamedType("typing.Callable")
        else:
            raise NotImplementedError(v.__class__.__name__)