from typing import Dict
import torch
from typing import Optional
from typing import Union
from typing import List
from typing import Tuple
from typing import KeysView


def detach_dict(data: Dict[str, torch.Tensor], keys: Optional[Union[List, Tuple, KeysView]] = None) -> Dict:
    """Return a detached copy of a dictionary. Only torch.Tensor's are detached.

    Parameters
    ----------
    data: Dict[str, torch.Tensor]
    keys: List, Tuple
        Subselection of keys to detach

    Returns
    -------
    Dictionary at the new device.
    """
    if keys is None:
        keys = data.keys()
    return {k: v.detach() for k, v in data.items() if k in keys if isinstance(v, torch.Tensor)}