def pileup_bases(pileupColumn, real_POS, cell_tag, UMI_tag, min_MAPQ,
    max_FLAG, min_LEN):
    """ 
    Pileup all reads mapped to the genome position.
    Filtering is also applied, including cell and UMI tags and read mapping 
    quality.
    """
    base_list, qual_list, UMIs_list, cell_list = [], [], [], []
    for pileupread in pileupColumn.pileups:
        if pileupread.is_del or pileupread.is_refskip:
            continue
        _read = pileupread.alignment
        if real_POS is not None:
            try:
                idx = _read.positions.index(real_POS - 1)
            except:
                continue
            _qual = _read.qqual[idx]
            _base = _read.query_alignment_sequence[idx].upper()
        else:
            query_POS = pileupread.query_position
            _qual = _read.qual[query_POS - 1]
            _base = _read.query_sequence[query_POS - 1].upper()
        if _read.mapq < min_MAPQ or _read.flag > max_FLAG or len(_read.
            positions) < min_LEN:
            continue
        if cell_tag is not None and _read.has_tag(cell_tag) == False:
            continue
        if UMI_tag is not None and _read.has_tag(UMI_tag) == False:
            continue
        if UMI_tag is not None:
            UMIs_list.append(_read.get_tag(UMI_tag))
        if cell_tag is not None:
            cell_list.append(_read.get_tag(cell_tag))
        base_list.append(_base)
        qual_list.append(_qual)
    return base_list, qual_list, UMIs_list, cell_list
