def resolve_type_to_most_specific(t: _GenericAlias) -> _GenericAlias: """Resolve Union in a type annotation to its most specific element * Use case: todo: extend to Optional :param t: :return: """ if hasattr(t, '__origin__'): if t.__origin__ == Union: # Return the argument with the highest number of bases # * If there are multiple 'specific options', return the first one (!) # * Doesn't cover nested Union which seems to be resolved to # a flat Union at runtime anyway. candidates = tuple( [a for a in t.__args__ if nbases(a) == nbases(max(t.__args__, key=nbases))] ) if len(candidates) == 1: return candidates[0] else: return t.__args__[0] elif issubclass(t.__origin__, Collection): # Recurse over arguments t.__args__ = tuple( [resolve_type_to_most_specific(a) for a in t.__args__] ) return t else: return t
def _wrap_generic_meta(t: _GenericAlias, args: List[type]) -> TypeResult: if t.__origin__ is tuple: tuple_args = tuple(args) # Handle the special case when t1 or t2 are empty tuples; TODO: investigate this if tuple_args == ((),): tuple_args = () return TypeInfo(Tuple[tuple_args]) elif is_callable(t): c = Callable.copy_with(tuple(args)) c.__polymorphic_tvars__ = getattr(t, '__polymorphic_tvars__', frozenset()) return TypeInfo(c) else: return TypeInfo(t.copy_with(tuple(args)))
def wrap_container(container_type: _GenericAlias, *args: type) -> TypeResult: """Return instance of type container_type with type variable arguments args, wrapped in instance of TypeInfo.""" return TypeInfo(container_type.copy_with(args))