<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def read_loom(filename: PathLike, sparse: bool = True, cleanup: bool = False, X_name: str = 'spliced', obs_names: str = 'CellID', var_names: str = 'Gene', dtype: str='float32', **kwargs) -> AnnData: """Read ``.loom``-formatted hdf5 file. This reads the whole file into memory. Beware that you have to explicitly state when you want to read the file as sparse data. Parameters filename The filename. sparse Whether to read the data matrix as sparse. cleanup: Whether to remove all obs/var keys that do not store more than one unique value. X_name: Loompy key where the data matrix is stored. obs_names: Loompy key where the observation/cell names are stored. var_names: Loompy key where the variable/gene names are stored. **kwargs: Arguments to loompy.connect """

    filename = fspath(filename)  # allow passing pathlib.Path objects
    from loompy import connect
    with connect(filename, 'r', **kwargs) as lc:

        if X_name not in lc.layers.keys(): X_name = ''
        X = lc.layers[X_name].sparse().T.tocsr() if sparse else lc.layers[X_name][()].T

        layers = OrderedDict()
        if X_name != '': layers['matrix'] = lc.layers[''].sparse().T.tocsr() if sparse else lc.layers[''][()].T
        for key in lc.layers.keys():
            if key != '': layers[key] = lc.layers[key].sparse().T.tocsr() if sparse else lc.layers[key][()].T

        obs = dict(lc.col_attrs)
        if obs_names in obs.keys(): obs['obs_names'] = obs.pop(obs_names)
        obsm_attrs = [k for k, v in obs.items() if v.ndim > 1 and v.shape[1] > 1]

        obsm = {}
        for key in obsm_attrs:
            obsm[key] = obs.pop(key)

        var = dict(lc.row_attrs)
        if var_names in var.keys(): var['var_names'] = var.pop(var_names)
        varm_attrs = [k for k, v in var.items() if v.ndim > 1 and v.shape[1] > 1]

        varm = {}
        for key in varm_attrs:
            varm[key] = var.pop(key)

        if cleanup:
            for key in list(obs.keys()):
                if len(set(obs[key])) == 1:
                    del obs[key]
            for key in list(var.keys()):
                if len(set(var[key])) == 1:
                    del var[key]

        adata = AnnData(
            X,
            obs=obs,  # not ideal: make the generator a dict...
            var=var,
            layers=layers,
            obsm=obsm if obsm else None,
            varm=varm if varm else None,
            dtype=dtype)
    return adata