def test_call_posargs(self): pytd = metadata.to_pytd({ 'tag': 'call', 'fn': 'Quack', 'posargs': [2], 'kwargs': {} }) self.assertEqual(pytd, 'Quack(2)')
def value_to_pytd_def(self, node, v, name): """Get a PyTD definition for this object. Args: node: The node. v: The object. name: The object name. Returns: A PyTD definition. """ if isinstance(v, abstract.Module): return pytd.Alias(name, pytd.Module(name, module_name=v.full_name)) elif isinstance(v, abstract.BoundFunction): d = self.value_to_pytd_def(node, v.underlying, name) assert isinstance(d, pytd.Function) sigs = tuple( sig.Replace(params=sig.params[1:]) for sig in d.signatures) return d.Replace(signatures=sigs) elif isinstance(v, attr_overlay.Attrs): ret = pytd.NamedType("typing.Callable") md = metadata.to_pytd(v.to_metadata()) return pytd.Annotated(ret, ("'pytype_metadata'", md)) elif (isinstance(v, abstract.PyTDFunction) and not isinstance(v, typing_overlay.TypeVar)): return pytd.Function( name=name, signatures=tuple(sig.pytd_sig for sig in v.signatures), kind=v.kind, flags=pytd.MethodFlag.abstract_flag(v.is_abstract)) elif isinstance(v, abstract.InterpreterFunction): return self._function_to_def(node, v, name) elif isinstance(v, abstract.SimpleFunction): return self._simple_func_to_def(node, v, name) elif isinstance(v, (abstract.ParameterizedClass, abstract.Union)): return pytd.Alias(name, v.get_instance_type(node)) elif isinstance(v, abstract.PyTDClass) and v.module: # This happens if a module does e.g. "from x import y as z", i.e., copies # something from another module to the local namespace. We *could* # reproduce the entire class, but we choose a more dense representation. return v.to_type(node) elif isinstance(v, typed_dict.TypedDictClass): return self._typed_dict_to_def(node, v, name) elif isinstance(v, abstract.PyTDClass): # a namedtuple instance assert name != v.name return pytd.Alias(name, pytd.NamedType(v.name)) elif isinstance(v, abstract.InterpreterClass): if v.official_name is None or name == v.official_name: return self._class_to_def(node, v, name) else: return pytd.Alias(name, pytd.NamedType(v.official_name)) elif isinstance(v, abstract.TypeParameter): return self._typeparam_to_def(node, v, name) elif isinstance(v, abstract.Unsolvable): return pytd.Constant(name, v.to_type(node)) else: raise NotImplementedError(v.__class__.__name__)
def test_call_kwargs(self): pytd = metadata.to_pytd({ 'tag': 'call', 'fn': 'Quack', 'posargs': (), 'kwargs': { 'volume': 4.5 } }) self.assertEqual(pytd, 'Quack(volume=4.5)')
def test_call_allargs(self): pytd = metadata.to_pytd({ 'tag': 'call', 'fn': 'Quack', 'posargs': [2, 'brown'], 'kwargs': { 'volume': 4.5, 'mode': 'correct' } }) self.assertEqual(pytd, "Quack(2, 'brown', volume=4.5, mode='correct')")
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 or v.instance is abstract_utils.DUMMY_CONTAINER): 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, attr_overlay.AttribInstance): ret = self.value_to_pytd_type(node, v.typ, seen, view) md = metadata.to_pytd(v.to_metadata()) return pytd.Annotated(ret, ("'pytype_metadata'", md)) elif isinstance(v, special_builtins.PropertyInstance): return pytd.NamedType("builtins.property") elif isinstance(v, typed_dict.TypedDict): return pytd.NamedType(v.props.name) elif isinstance(v, abstract.FUNCTION_TYPES): try: signatures = function.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, abstract.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.Alias(v.name, pytd.Module(v.name, module_name=v.full_name)) 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): ret = self.value_instance_to_pytd_type(node, v.cls, v, seen=seen, view=view) ret.Visit( visitors.FillInLocalPointers( {"builtins": self.ctx.loader.builtins})) return ret elif isinstance(v, abstract.Union): return pytd_utils.JoinTypes( self.value_to_pytd_type(node, o, seen, view) for o in v.options) 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") elif isinstance(v, abstract.FinalAnnotation): param = self.value_to_pytd_type(node, v.annotation, seen, view) return pytd.GenericType(base_type=pytd.NamedType("typing.Final"), parameters=(param, )) else: raise NotImplementedError(v.__class__.__name__)
def test_deprecated(self): pytd = metadata.to_pytd({ 'tag': 'Deprecated', 'reason': 'squished by duck' }) self.assertEqual(pytd, "Deprecated('squished by duck')")
def test_no_tag(self): self.assertEqual(metadata.to_pytd({}), '{}')
def test_noncall_tag(self): self.assertEqual(metadata.to_pytd({'tag': 'sneeze'}), "{'tag': 'sneeze'}")