def get_imports_for_annotation(anno: Any) -> ImportMap: """Return the imports (module, name) needed for the type in the annotation""" imports = ImportMap() if ( anno is inspect.Parameter.empty or anno is inspect.Signature.empty or not (isinstance(anno, type) or is_any(anno) or is_union(anno) or is_generic(anno)) or anno.__module__ == 'builtins' ): return imports if is_any(anno): imports['typing'].add('Any') elif _is_optional(anno): imports['typing'].add('Optional') elem_type = _get_optional_elem(anno) elem_imports = get_imports_for_annotation(elem_type) imports.merge(elem_imports) elif is_generic(anno): if is_union(anno): imports['typing'].add('Union') else: imports[anno.__module__].add( _get_import_for_qualname(qualname_of_generic(anno))) elem_types = anno.__args__ or [] for et in elem_types: elem_imports = get_imports_for_annotation(et) imports.merge(elem_imports) else: name = _get_import_for_qualname(anno.__qualname__) imports[anno.__module__].add(name) return imports
def type_to_dict(typ: type) -> TypeDict: """Convert a type into a dictionary representation that we can store. The dictionary must: 1. Be encodable as JSON 2. Contain enough information to let us reify the type """ if is_typed_dict(typ): return typed_dict_to_dict(typ) # Union and Any are special cases that aren't actually types. if is_union(typ): qualname = 'Union' elif is_any(typ): qualname = 'Any' elif is_generic(typ): qualname = qualname_of_generic(typ) else: qualname = typ.__qualname__ d: TypeDict = { 'module': typ.__module__, 'qualname': qualname, } elem_types = getattr(typ, '__args__', None) if elem_types and is_generic(typ): # empty typing.Tuple is weird; the spec says it should be Tuple[()], # which results in __args__ of `((),)` if elem_types == ((),): elem_types = () d['elem_types'] = [type_to_dict(t) for t in elem_types] return d
def type_from_dict(d: TypeDict) -> type: """Given a dictionary produced by type_to_dict, return the equivalent type. Raises: NameLookupError if we can't reify the specified type InvalidTypeError if the named type isn't actually a type """ module, qualname = d['module'], d['qualname'] if d.get('is_typed_dict', False): return typed_dict_from_dict(d) if module == 'builtins' and qualname in _HIDDEN_BUILTIN_TYPES: typ = _HIDDEN_BUILTIN_TYPES[qualname] else: typ = get_name_in_module(module, qualname) if not ( isinstance(typ, type) or is_any(typ) or is_generic(typ) ): raise InvalidTypeError( f"Attribute specified by '{qualname}' in module '{module}' " f"is of type {type(typ)}, not type." ) elem_type_dicts = d.get('elem_types') if elem_type_dicts is not None and is_generic(typ): elem_types = tuple(type_from_dict(e) for e in elem_type_dicts) # mypy complains that a value of type `type` isn't indexable. That's # true, but we know typ is a subtype that is indexable. Even checking # with hasattr(typ, '__getitem__') doesn't help typ = typ[elem_types] # type: ignore return typ
def rewrite(self, typ): if is_any(typ): typname = 'Any' elif is_union(typ): typname = 'Union' elif is_generic(typ): typname = name_of_generic(typ) else: typname = getattr(typ, '__name__', None) rewriter = getattr(self, 'rewrite_' + typname, None) if typname else None if rewriter: return rewriter(typ) return self.generic_rewrite(typ)
def rewrite(self, typ): if is_any(typ): typname = 'Any' elif is_union(typ): typname = 'Union' elif is_typed_dict(typ): typname = 'TypedDict' elif is_generic(typ): typname = name_of_generic(typ) else: typname = getattr(typ, '__name__', None) rewriter = getattr(self, 'rewrite_' + typname, None) if typname else None if rewriter: return rewriter(typ) if isinstance(typ, TypeVar): return self.rewrite_type_variable(typ) return self.generic_rewrite(typ)
def type_to_dict(typ: type) -> TypeDict: """Convert a type into a dictionary representation that we can store. The dictionary must: 1. Be encodable as JSON 2. Contain enough information to let us reify the type """ # Union and Any are special cases that aren't actually types. if is_union(typ): qualname = 'Union' elif is_any(typ): qualname = 'Any' elif is_generic(typ): qualname = qualname_of_generic(typ) else: qualname = typ.__qualname__ d: TypeDict = { 'module': typ.__module__, 'qualname': qualname, } elem_types = getattr(typ, '__args__', None) if elem_types and is_generic(typ): d['elem_types'] = [type_to_dict(t) for t in elem_types] return d
def _is_empty(self, typ): args = getattr(typ, '__args__', []) return args and all(is_any(e) for e in args)