Make silent mutations to the given codon lists to remove any undesirable 
    sequences that are present within it.  Undesirable sequences include 
    restriction sites, which may be optionally specified as a second argument, 
    and homopolymers above a pre-defined length.  The return value is the 
    number of corrections made to the codon list.

def sanitize_codon_list(codon_list, forbidden_seqs=()):
    """
    Make silent mutations to the given codon lists to remove any undesirable 
    sequences that are present within it.  Undesirable sequences include 
    restriction sites, which may be optionally specified as a second argument, 
    and homopolymers above a pre-defined length.  The return value is the 
    number of corrections made to the codon list.
    """

    # Unit test missing for:
    #   Homopolymer fixing

    for codon in codon_list:
        if len(codon) != 3:
            raise ValueError("Codons must have exactly 3 bases: '{}'".format(codon))

    # Compile a collection of all the sequences we don't want to appear in the 
    # gene.  This includes the given restriction sites and their reverse 
    # complements, plus any homopolymers above a pre-defined length.

    bad_seqs = set()
    
    bad_seqs.union(
            restriction_sites.get(seq, seq)
            for seq in forbidden_seqs)

    bad_seqs.union(
            dna.reverse_complement(seq)
            for seq in bad_seqs)

    bad_seqs.union(
            base * (gen9.homopolymer_max_lengths[base] + 1)
            for base in dna.dna_bases)

    bad_seqs = [
            dna.dna_to_re(bs)
            for bs in bad_seqs]

    # Remove every bad sequence from the gene by making silent mutations to the 
    # codon list.
    
    num_corrections = 0

    for bad_seq in bad_seqs:
        while remove_bad_sequence(codon_list, bad_seq, bad_seqs):
            num_corrections += 1

    return num_corrections