def test_named_type_with_module(self): """Test NamedTypeWithModule().""" self.assertEqual(pytd_utils.NamedTypeWithModule("name"), pytd.NamedType("name")) self.assertEqual(pytd_utils.NamedTypeWithModule("name", None), pytd.NamedType("name")) self.assertEqual(pytd_utils.NamedTypeWithModule("name", "package"), pytd.NamedType("package.name"))
def value_instance_to_pytd_type(self, node, v, instance, seen, view): """Get the PyTD type an instance of this object would have. Args: node: The node. v: The object. instance: The instance. seen: Already seen instances. view: A Variable -> binding map. Returns: A PyTD type. """ if isinstance(v, abstract.Union): return pytd.UnionType(tuple( self.value_instance_to_pytd_type(node, t, instance, seen, view) for t in v.options)) elif isinstance(v, abstract.AnnotationContainer): return self.value_instance_to_pytd_type( node, v.base_cls, instance, seen, view) elif isinstance(v, mixin.Class): if not self._detailed and v.official_name is None: return pytd.AnythingType() if seen is None: # We make the set immutable to ensure that the seen instances for # different parameter values don't interfere with one another. seen = frozenset() if instance in seen: # We have a circular dependency in our types (e.g., lst[0] == lst). Stop # descending into the type parameters. type_params = () else: type_params = tuple(t.name for t in v.template) if instance is not None: seen |= {instance} type_arguments = self._value_to_parameter_types( node, v, instance, type_params, seen, view) base = pytd_utils.NamedTypeWithModule(v.official_name or v.name, v.module) if self._is_tuple(v, instance): if type_arguments: homogeneous = False else: homogeneous = True type_arguments = [pytd.NothingType()] elif v.full_name == "typing.Callable": homogeneous = not isinstance(v, abstract.CallableClass) else: homogeneous = len(type_arguments) == 1 return pytd_utils.MakeClassOrContainerType( base, type_arguments, homogeneous) elif isinstance(v, abstract.TypeParameter): # We generate the full definition because, if this type parameter is # imported, we will need the definition in order to declare it later. return self._typeparam_to_def(node, v, v.name) elif isinstance(v, typing_overlay.NoReturn): return pytd.NothingType() else: log.info("Using ? for instance of %s", v.name) return pytd.AnythingType()
def value_instance_to_pytd_type(self, node, v, instance, seen, view): """Get the PyTD type an instance of this object would have. Args: node: The node. v: The object. instance: The instance. seen: Already seen instances. view: A Variable -> binding map. Returns: A PyTD type. """ if isinstance(v, abstract.Union): return pytd.UnionType( tuple( self.value_instance_to_pytd_type(node, t, instance, seen, view) for t in v.options)) elif isinstance(v, abstract.AnnotationContainer): return self.value_instance_to_pytd_type(node, v.base_cls, instance, seen, view) elif isinstance(v, abstract.LiteralClass): if not v.value: # TODO(b/173742489): Remove this workaround once we support literal # enums. return pytd.AnythingType() if isinstance(v.value.pyval, (str, bytes)): # Strings are stored as strings of their representations, prefix and # quotes and all. value = repr(v.value.pyval) elif isinstance(v.value.pyval, bool): # True and False are stored as pytd constants. value = self.vm.lookup_builtin(f"builtins.{v.value.pyval}") else: # Ints are stored as their literal values. Note that Literal[None] or a # nested literal will never appear here, since we simplified it to None # or unnested it, respectively, in typing_overlay. Literal[<enum>] does # not appear here yet because it is unsupported. assert isinstance(v.value.pyval, int), v.value.pyval value = v.value.pyval return pytd.Literal(value) elif isinstance(v, class_mixin.Class): if not self._detailed and v.official_name is None: return pytd.AnythingType() if seen is None: # We make the set immutable to ensure that the seen instances for # different parameter values don't interfere with one another. seen = frozenset() if instance in seen: # We have a circular dependency in our types (e.g., lst[0] == lst). Stop # descending into the type parameters. type_params = () else: type_params = tuple(t.name for t in v.template) if instance is not None: seen |= {instance} type_arguments = self._value_to_parameter_types( node, v, instance, type_params, seen, view) base = pytd_utils.NamedTypeWithModule(v.official_name or v.name, v.module) if self._is_tuple(v, instance): homogeneous = False elif v.full_name == "typing.Callable": homogeneous = not isinstance(v, abstract.CallableClass) else: homogeneous = len(type_arguments) == 1 return pytd_utils.MakeClassOrContainerType(base, type_arguments, homogeneous) elif isinstance(v, abstract.TypeParameter): # We generate the full definition because, if this type parameter is # imported, we will need the definition in order to declare it later. return self._typeparam_to_def(node, v, v.name) elif isinstance(v, typing_overlay.NoReturn): return pytd.NothingType() else: log.info("Using Any for instance of %s", v.name) return pytd.AnythingType()