import asyncio
import typing


async def uncancellable(f: asyncio.Future,
                        raise_cancel: bool = True
                        ) -> typing.Any:
    """Uncancellable execution of a Future.

    Future is shielded and its execution cannot be interrupted.

    If `raise_cancel` is `True` and the Future gets canceled,
    `asyncio.CancelledError` is reraised after the Future finishes.

    Warning:
        If `raise_cancel` is `False`, this method suppresses
        `asyncio.CancelledError` and stops its propagation. Use with
        caution.

    Args:
        f: future
        raise_cancel: raise CancelledError flag

    Returns:
        future's result

    """
    exception = None
    task = asyncio.ensure_future(f)
    while not task.done():
        try:
            await asyncio.shield(task)
        except asyncio.CancelledError as e:
            if raise_cancel:
                exception = e
        except Exception:
            pass
    if exception:
        raise exception
    return task.result()