def check_recombination(self): epc = EditProposalCreator(self.control_sample.primary_base_calls, use_ctrl_trace=True, sanger_object=self.control_sample) if len(self.donor_odn) > len( self.control_sample.primary_base_calls) * 0.75: self.warnings.append( "Large Donor of {} bp compared to control sequence of {} bp". format(len(self.donor_odn), len(self.control_sample.primary_base_calls))) #int((len(re.split("(-+)", alignment[0])) - 3) / 2) try: cutsite = self.guide_targets[0].cutsite hr_proposal, changed_bases, odn_start_pos, aln = epc.homologous_recombination_proposal( cutsite=cutsite, donor_sequence=self.donor_odn) self.recombined_seq = hr_proposal.sequence self.recombination_changed_bases = changed_bases self.odn_start_pos = odn_start_pos self.donor_alignment = aln n_splits = int( (len(re.split("(-+)", aln.all_aligned_seqs[0])) - 3) / 2) if n_splits > 0: self.warnings.append( "{} donor integration sites".format(n_splits + 1)) except Exception as e: self.warnings.append( "Could not analyze homologous recombination case: {}".format( e)) self.donor_odn = None
def check_recombination(self): epc = EditProposalCreator(self.control_sample.primary_base_calls, use_ctrl_trace=True, sanger_object=self.control_sample) try: cutsite = self.guide_targets[0].cutsite hr_proposal, changed_bases, odn_start_pos, aln = epc.homologous_recombination_proposal( cutsite=cutsite, donor_sequence=self.donor_odn) self.recombined_seq = hr_proposal.sequence self.recombination_changed_bases = changed_bases self.odn_start_pos = odn_start_pos self.donor_alignment = aln except Exception as e: self.warnings.append( "Could not analyze homologous recombination case: {}".format( e)) self.donor_odn = None
def test_human_readable_sequence_single_edit_proposal(): wt_basecalls = 'ACTGCCTGCACCTGTCCCCATAGAAATCCGCTTTACGGAGAGTCACTAGACTAGGACCCCCATAAATTTCACGACAGGGACTAGACCTTGACTGGATA' epc = EditProposalCreator(wt_basecalls, use_ctrl_trace=False) proposal = epc.single_cut_edit_proposal(27, 'g1', del_before=4) # test default padding seq = proposal.human_readable_sequence() assert seq == 'TGCCTGCACCTGTCCCCATAG----|CCGCTTTACGGAGAGTCACTAGACTAGGACCCCCATAAATTTCACGACAG' # test custom padding seq = proposal.human_readable_sequence(bp_before_cutsite=10, bp_after_cutsite=15) assert seq == 'CCATAG----|CCGCTTTACGGAGAG' # test passing in out of bounds padding values (should default to returning the entire proposed sequence) seq = proposal.human_readable_sequence(bp_before_cutsite=500, bp_after_cutsite=500) assert seq == 'ACTGCCTGCACCTGTCCCCATAG----|CCGCTTTACGGAGAGTCACTAGACTAGGACCCCCATAAATTTCACGACAGGGACTAGACCTTGACTGGAT' # test passing in inf values (should return the the entire proposed sequence) seq = proposal.human_readable_sequence(bp_before_cutsite=float('inf'), bp_after_cutsite=float('inf')) assert seq == 'ACTGCCTGCACCTGTCCCCATAG----|CCGCTTTACGGAGAGTCACTAGACTAGGACCCCCATAAATTTCACGACAGGGACTAGACCTTGACTGGAT'
def test_human_readable_sequence_multiplex_proposal(): wt_basecalls = ('CCCATAAATCCGCTTTACAGTCACTAGACTAGGACCAATTTCACGACAGGGACTAGACCTTGCTGGATAGCACCTGTCCCCATAGAAATGGCTATGGA' 'AAGCCTTTGGGTTATTTGCGGCACCTGTCCCCATAGAAATGGCTATGGAAAGCCTTTGGGTTATTTGCG') epc = EditProposalCreator(wt_basecalls, use_ctrl_trace=False) # test close together dropout default padding close_together_dropout_proposal = epc.multiplex_proposal(30, 50, 'g1', 'g2', dropout=True) seq = close_together_dropout_proposal.human_readable_sequence() assert seq == 'AAATCCGCTTTACAGTCACTAGACT|--------------------|GACTAGACCTTGCTGGATAGCACCTGTCCC' # test far apart dropout default padding far_apart_dropout_proposal = epc.multiplex_proposal(30, 90, 'g1', 'g2', dropout=True) seq = far_apart_dropout_proposal.human_readable_sequence() assert seq == ('AAATCCGCTTTACAGTCACTAGACT|------------------------------------------------------------|GCTATGGAAAGC' 'CTTTGGGTTATTT') # test far apart insertion default padding far_apart_dropout_proposal = epc.multiplex_proposal(30, 90, 'g1', 'g2', dropout=False, cut1_ins=2, cut2_ins=4) seq = far_apart_dropout_proposal.human_readable_sequence() assert seq == ('ATCCGCTTTACAGTCACTAGACTnn|AGGACCAATTTCACGACAGGGACTAGACCTTGCTGGATAGCACCTGTCCCCATAGAAATGnnnn|GCTATGGA' 'AAGCCTTTGGGTTATTT')
def test_generated_trace(): seq = "ATNCG" epc = EditProposalCreator(seq, use_ctrl_trace=False) expected_trace = {'A':[], 'T':[], 'C':[], 'G':[]} for base in seq: if base == 'N': for color in expected_trace.keys(): expected_trace[color].append(0.25) else: for color in epc.base_order: if color == base: expected_trace[color].append(0.97) else: expected_trace[color].append(0.01) assert epc.wt_trace == expected_trace
def test_single_cut(): wt_basecalls = "GCACCTGTCCCCATAGAAAT" epc = EditProposalCreator(wt_basecalls, use_ctrl_trace=False) proposal = epc.single_cut_edit_proposal(10, "test", del_before=4) assert proposal.sequence == "GCACCTCCATAGAAAT" del_after_proposal = epc.single_cut_edit_proposal(10, "test", del_after=3) assert del_after_proposal.sequence == "GCACCTGTCCTAGAAAT" ins_proposal = epc.single_cut_edit_proposal(6, "test", insertion=2) assert ins_proposal.sequence.upper() == "GCACCTNNGTCCCCATAGAAAT" bad_config = epc.single_cut_edit_proposal(2, "bad", del_before=5) assert bad_config.sequence == "ACCTGTCCCCATAGAAAT"
def test_multiplex_cut(): wt_basecalls = "GCACCTGTCCCCATAGAAATGGCTATGGAAAGCCTTTGGGTTATTTGCG" "GCACCTGTCC-CCATAGAAATGGCTATGGAAAGCCT-TTGGGTTATTTGCG" epc = EditProposalCreator(wt_basecalls, use_ctrl_trace=False) dropout_proposal = epc.multiplex_proposal(10, 35, "test1", "test2", dropout=True) assert dropout_proposal.sequence == "GCACCTGTCCTTGGGTTATTTGCG" assert dropout_proposal.summary.startswith('-25:md') dropout_ins_proposal = epc.multiplex_proposal(10, 35, "test1", "test2", dropout=True, cut1_ins=2, cut2_ins=3) assert dropout_ins_proposal.sequence == "GCACCTGTCCnnTTGGGTTATTTGCG" indep_cut = epc.multiplex_proposal(10, 35, "test1", "test2", cut1_del=(4, 0), cut2_del=(0, 3)) assert indep_cut.sequence == "GCACCTCCATAGAAATGGCTATGGAAAGCCTGGTTATTTGCG" assert indep_cut.summary.startswith('-7:m-4[test1]') indep_cut2 = epc.multiplex_proposal(10, 35, "test1", "test2", cut1_del=(-4, 0), cut2_del=(3, 0)) assert indep_cut2.sequence == "GCACCTGTCCCCATAGAAATGGCTATGGAAAGTTGGGTTATTTGCG"
def _generate_edit_proposals(self): epc = EditProposalCreator(self.control_sample.primary_base_calls, use_ctrl_trace=True, sanger_object=self.control_sample) proposals = [] # only consider HR for first guide_target # we have already run homologous_recombination_proposal earlier, so no need to catch exceptions if self.donor_odn is not None: cutsite = self.guide_targets[0].cutsite hr_proposal, changed_bases, odn_start_pos, aln = epc.homologous_recombination_proposal( cutsite=cutsite, donor_sequence=self.donor_odn) proposals.append(hr_proposal) # single cut cases for guide_target in self.guide_targets: cutsite = guide_target.cutsite # deletion case deletion_befores = list(range(self.indel_max_size + 1)) deletion_afters = list(range(self.indel_max_size + 1)) for deletion_before in deletion_befores: for deletion_after in deletion_afters: ep = epc.single_cut_edit_proposal( cutsite, guide_target.label, del_before=deletion_before, del_after=deletion_after) proposals.append(ep) insertions = list(range(self.indel_max_size)) for insertion in insertions: ep = epc.single_cut_edit_proposal(cutsite, guide_target.label, insertion=insertion) proposals.append(ep) # multiplex case # we limit the deletion sizes here deletion_befores = list(range(5)) deletion_afters = list(range(5)) insertions = list(range(3)) for combo in combinations(self.guide_targets, 2): guide1 = min(combo, key=lambda x: x.cutsite) guide2 = max(combo, key=lambda x: x.cutsite) cutsite1 = guide1.cutsite cutsite2 = guide2.cutsite if cutsite1 == cutsite2: print("Warning: cutsite1 == cutsite2") continue label1 = guide1.label label2 = guide2.label for cut1_before in deletion_befores: for cut1_after in deletion_afters: for cut2_before in deletion_befores: for cut2_after in deletion_afters: independent_cut = epc.multiplex_proposal( cutsite1, cutsite2, label1, label2, cut1_del=(cut1_before, cut1_after), cut2_del=(cut2_before, cut2_after)) if independent_cut: proposals.append(independent_cut) # dropout case for cut1_before in deletion_befores: for cut2_after in deletion_afters: dropout = epc.multiplex_proposal(cutsite1, cutsite2, label1, label2, cut1_del=(cut1_before, 0), cut2_del=(0, cut2_after), dropout=True) if dropout: proposals.append(dropout) for insertion1 in insertions: for insertion2 in insertions: cut_and_insert = epc.multiplex_proposal( cutsite1, cutsite2, label1, label2, cut1_ins=insertion1, cut2_ins=insertion2) if cut_and_insert: proposals.append(cut_and_insert) # dropout insertion case for insertion in insertions: dropout_and_insert = epc.multiplex_proposal(cutsite1, cutsite2, label1, label2, cut1_ins=insertion, dropout=True) if dropout_and_insert: proposals.append(dropout_and_insert) self.proposals = proposals
def _generate_edit_proposals(self): epc = EditProposalCreator(self.control_sample.primary_base_calls, use_ctrl_trace=True, sanger_object=self.control_sample) proposals = [] if self.donor_odn is not None: cutsite = self.guide_targets[0].cutsite hr_proposal, changed_bases, odn_start_pos, aln = epc.homologous_recombination_proposal( cutsite=cutsite, donor_sequence=self.donor_odn) proposals.append(hr_proposal) # single cut cases for guide_target in self.guide_targets: cutsite = guide_target.cutsite # deletion case deletion_befores = list(range(self.indel_max_size + 1)) deletion_afters = list(range(self.indel_max_size + 1)) for deletion_before in deletion_befores: for deletion_after in deletion_afters: indel_size = -(deletion_before + deletion_after) if self._should_skip_proposal(indel_size): continue ep = epc.single_cut_edit_proposal( cutsite, guide_target.label, del_before=deletion_before, del_after=deletion_after) proposals.append(ep) insertions = list(range(self.indel_max_size + 1)) for insertion in insertions: if self._should_skip_proposal(insertion): continue ep = epc.single_cut_edit_proposal(cutsite, guide_target.label, insertion=insertion) proposals.append(ep) # multiplex case # we limit the deletion sizes here deletion_befores = list(range(5)) deletion_afters = list(range(5)) insertions = list(range(3)) for combo in combinations(self.guide_targets, 2): guide1 = min(combo, key=lambda x: x.cutsite) guide2 = max(combo, key=lambda x: x.cutsite) cutsite1 = guide1.cutsite cutsite2 = guide2.cutsite if cutsite1 == cutsite2: print("Warning: cutsite1 == cutsite2") continue label1 = guide1.label label2 = guide2.label for cut1_before in deletion_befores: for cut1_after in deletion_afters: for cut2_before in deletion_befores: for cut2_after in deletion_afters: independent_cut = epc.multiplex_proposal( cutsite1, cutsite2, label1, label2, cut1_del=(cut1_before, cut1_after), cut2_del=(cut2_before, cut2_after)) if independent_cut: proposals.append(independent_cut) # dropout case for cut1_before in deletion_befores: for cut2_after in deletion_afters: dropout = epc.multiplex_proposal(cutsite1, cutsite2, label1, label2, cut1_del=(cut1_before, 0), cut2_del=(0, cut2_after), dropout=True) if dropout: proposals.append(dropout) for insertion1 in insertions: for insertion2 in insertions: cut_and_insert = epc.multiplex_proposal( cutsite1, cutsite2, label1, label2, cut1_ins=insertion1, cut2_ins=insertion2) if cut_and_insert: proposals.append(cut_and_insert) # dropout insertion case for insertion in insertions: dropout_and_insert = epc.multiplex_proposal(cutsite1, cutsite2, label1, label2, cut1_ins=insertion, dropout=True) if dropout_and_insert: proposals.append(dropout_and_insert) #removing degenerate proposals seen = [] self.proposals = list( filter( lambda x: seen.append(x.sequence) is None if x.sequence not in seen else False, proposals))
def test_wt_proposal(): wt_basecalls = "GCACCTGTCCCCGGGGAAAT" epc = EditProposalCreator(wt_basecalls, use_ctrl_trace=False) proposal = epc.single_cut_edit_proposal(10, "test") assert proposal.sequence == "GCACCTGTCCCCGGGGAAAT"
def test_bad_multiplex(): wt_basecalls = "GCACCTGTCCCCATAGAAATGGCTATGGAAAGCCTTTGGGTTATTTGCG" epc = EditProposalCreator(wt_basecalls, use_ctrl_trace=False) with pytest.raises(Exception): epc.multiplex_proposal(20, 10, "test1", "test2", dropout=True)
def test_req_ctrl_trace(): with pytest.raises(Exception): epc = EditProposalCreator("ATCG", use_ctrl_trace=True)