def _cleave(
    sequence,
    sites,
    missed_cleavages,
    min_length,
    max_length,
    semi,
    clip_nterm_met,
):
    """Digest a protein sequence into its constituent peptides.

    Parameters
    ----------
    sequence : str
        A protein sequence to digest.
    sites : list of int
        The cleavage sites.
    missed_cleavages : int, optional
        The maximum number of allowed missed cleavages.
    min_length : int, optional
        The minimum peptide length.
    max_length : int, optional
        The maximum peptide length.
    semi : bool
        Allow semi-enzymatic cleavage.
    clip_nterm_met : bool
        Clip the N-Terminal methionine

    Returns
    -------
    peptides : set of str
        The peptides resulting from the digested sequence.
    """
    peptides = set()

    # Do the digest
    for start_idx, start_site in enumerate(sites):
        for diff_idx in range(1, missed_cleavages + 2):
            end_idx = start_idx + diff_idx
            if end_idx >= len(sites):
                continue

            end_site = sites[end_idx]
            peptide = sequence[start_site:end_site]
            if len(peptide) < min_length or len(peptide) > max_length:
                continue

            peptides.add(peptide)

            if clip_nterm_met and not start_idx and peptide.startswith("M"):
                if len(peptide[1:]) >= min_length:
                    peptides.add(peptide[1:])

            # Handle semi:
            if semi:
                for idx in range(1, len(peptide)):
                    sub_pep_len = len(peptide) - idx
                    if sub_pep_len < min_length:
                        break

                    if sub_pep_len > max_length:
                        continue

                    semi_pep = {peptide[idx:], peptide[:-idx]}
                    peptides = peptides.union(semi_pep)

    return peptides