def test_master_mix_dunder(): # Just quickly call all the dunders to make sure they're doing something. # The `test_reaction_...()` tests make sure these methods actually work. mm = MasterMix() mm.solvent = 'w' # `__repr__()` assert repr(mm) == "MasterMix('w')" # `__getitem__()` mm['x'].volume = '1 µL' assert mm.reaction['x'].volume == '1 µL' # `__iter__()` for reagent, expected in zip(mm, ['w', 'x']): assert reagent.name == expected # `__contains__()` assert 'w' in mm assert 'x' in mm assert 'y' not in mm # `__len__()` assert len(mm) == 2 # `__delitem__()` del mm['x'] assert len(mm) == 1
def test_master_mix_setattr(): mm = MasterMix() mm.volume = '1 µL' assert mm.reaction.volume == '1 µL' mm.solvent = 'w' assert mm.reaction.solvent == 'w'
def test_master_mix_replace_text(): mm = MasterMix.from_text("""\ Reagent Stock Volume MM? ========= ===== ======== === water to 10 µL yes long name 10x 1 µL yes """) assert str(mm) == """\ Reagent Stock Volume ────────────────────────── water 9.00 µL long name 10x 1.00 µL ────────────────────────── 10.00 µL""" mm.replace_text('long ', '') assert str(mm) == """\ Reagent Stock Volume ──────────────────────── water 9.00 µL name 10x 1.00 µL ──────────────────────── 10.00 µL""" mm.replace_text('name', 'extra long name') assert str(mm) == """\
def test_master_mix_format_text_0_volume_reagent(): mm = MasterMix.from_text("""\ Reagent Stock Volume MM? ======== ===== ======= === water to 3 µL yes buffer 3x 1 µL yes cofactor 3x 1 µL yes enzyme 3x 1 µL no """) mm.num_reactions = 2 mm.extra_fraction = 0 mm.extra_reactions = 0 assert str(mm) == """\ Reagent Stock Volume 2x ───────────────────────────────── buffer 3x 1.00 µL 2.00 µL cofactor 3x 1.00 µL 2.00 µL enzyme 3x 1.00 µL ───────────────────────────────── 3.00 µL 2.00 µL/rxn""" mm['buffer'].volume = 0.001, 'µL' assert str(mm) == """\ Reagent Stock Volume 2x ───────────────────────────────── water 1.00 µL 2.00 µL cofactor 3x 1.00 µL 2.00 µL enzyme 3x 1.00 µL ───────────────────────────────── 3.00 µL 2.00 µL/rxn""" mm['buffer'].volume = -0.001, 'µL' assert str(mm) == """\
def test_master_mix_format_text(format): mm = MasterMix.from_text("""\ Reagent Stock Volume MM? ======= ===== ======== === water to 10 µL yes buffer 10x 1 µL yes enzyme 5x 2 µL no """) mm.num_reactions = 1 assert format(mm) == """\ Reagent Stock Volume ──────────────────────── water 7.00 µL buffer 10x 1.00 µL enzyme 5x 2.00 µL ──────────────────────── 10.00 µL""" mm.num_reactions = 2 mm.extra_fraction = 0 mm.extra_reactions = 0 assert format(mm) == """\ Reagent Stock Volume 2x ────────────────────────────────── water 7.00 µL 14.00 µL buffer 10x 1.00 µL 2.00 µL enzyme 5x 2.00 µL ────────────────────────────────── 10.00 µL 8.00 µL/rxn""" mm.show_master_mix = False mm.show_1x = True mm.show_totals = True assert format(mm) == """\ Reagent Stock Volume ──────────────────────── water 7.00 µL buffer 10x 1.00 µL enzyme 5x 2.00 µL ──────────────────────── 10.00 µL""" mm.show_master_mix = True mm.show_1x = False mm.show_totals = True assert format(mm) == """\ Reagent Stock 2x ──────────────────────── water 14.00 µL buffer 10x 2.00 µL enzyme 5x ──────────────────────── 8.00 µL/rxn""" mm.show_master_mix = True mm.show_1x = True mm.show_totals = False assert format(mm) == """\
def test_master_mix_getattr_raises(): mm = MasterMix() with pytest.raises(AttributeError, match="'MasterMix' object has no attribute 'undefined'"): mm.undefined # Try to trick to code that munges the error message. with pytest.raises(AttributeError, match="'MasterMix' object has no attribute 'Reaction'"): mm.Reaction
def hydroxide_hydrolysis(): rxn = MasterMix("""\ Reagent Stock Volume ============= ====== ======== water to 10 µL IVTT reaction 2.5 µL EDTA 500 mM 1.25 µL NaOH 1 M 1.67 µL """) return f"""\
def rnase_digestion(): rxn = MasterMix("""\ Reagent Stock Volume ============= ====== ======== water to 10 µL IVTT reaction 2.5 µL EDTA 500 mM 1.25 µL RNase A 1.0 µL """) return f"""\
def carbonate_hydrolysis(): rxn = MasterMix("""\ Reagent Stock Volume ======================== ====== ======== water to 10 µL IVTT reaction 2.5 µL EDTA 500 mM 1.25 µL sodium carbonate, pH 9.2 100 mM 5 µL """) return f"""\
def test_master_mix_scale(params): mm = MasterMix() mm.num_reactions = params['n'] mm.solvent = 'w' mm.volume = params['vol_rxn'] mm['x'].volume = params['vol_x'] mm['w'].master_mix = True mm['x'].master_mix = True if 'fraction' in params: mm.extra_fraction = params['fraction'] assert mm.extra_percent == pytest.approx(params['fraction'] * 100) if 'percent' in params: mm.extra_percent = params['percent'] assert mm.extra_fraction == pytest.approx(params['percent'] / 100) if 'reactions' in params: mm.extra_reactions = params['reactions'] if 'min_vol' in params: mm.extra_min_volume = params['min_vol'] assert mm.get_scale() == pytest.approx(params['expected'])
def get_reaction(self): rxn = MasterMix(self.buffers[self.transfer_type]) rxn.extra_percent = 20 rxn.extra_min_volume = '1 µL' if isinstance(self.samples, int): rxn.num_reactions = self.samples else: rxn['DNA'].name = ','.join(self.samples) rxn.num_reactions = len(self.samples) if x := self.num_spots: rxn.num_reactions = x
def test_master_mix_format_text_scale_header(): mm = MasterMix.from_text("""\ Reagent Stock Volume MM? ======= ===== ======== === water to 10 µL yes buffer 10x 1 µL yes enzyme 5x 2 µL no """) # Scale is an exact integer ending with zero. mm.num_reactions = 10 mm.extra_percent = 0 assert str(mm) == """\ Reagent Stock Volume 10x ────────────────────────────────── water 7.00 µL 70.00 µL buffer 10x 1.00 µL 10.00 µL enzyme 5x 2.00 µL ────────────────────────────────── 10.00 µL 8.00 µL/rxn""" # Scale is an exact integer not ending with zero. mm.extra_percent = 10 assert str(mm) == """\ Reagent Stock Volume 11x ────────────────────────────────── water 7.00 µL 77.00 µL buffer 10x 1.00 µL 11.00 µL enzyme 5x 2.00 µL ────────────────────────────────── 10.00 µL 8.00 µL/rxn""" # Scale is exactly represented with one decimal point. mm.extra_percent = 11 assert str(mm) == """\ Reagent Stock Volume 11.1x ────────────────────────────────── water 7.00 µL 77.70 µL buffer 10x 1.00 µL 11.10 µL enzyme 5x 2.00 µL ────────────────────────────────── 10.00 µL 8.00 µL/rxn""" # Scale is not exactly represented with one decimal point. mm.extra_percent = 11.1 assert str(mm) == """\
def test_master_mix_format_text_no_solvent(): mm = MasterMix.from_text("""\ Reagent Stock Volume MM? ======== ===== ======= === buffer 3x 1 µL yes cofactor 3x 1 µL yes enzyme 3x 1 µL no """) mm.num_reactions = 1 assert str(mm) == """\ Reagent Stock Volume ──────────────────────── buffer 3x 1.00 µL cofactor 3x 1.00 µL enzyme 3x 1.00 µL ──────────────────────── 3.00 µL""" mm.num_reactions = 2 mm.extra_fraction = 0 mm.extra_reactions = 0 assert str(mm) == """\
def test_master_mix_pickle(): from pickle import loads, dumps # Just checking that this doesn't raise. loads(dumps(MasterMix()))
args = docopt.docopt(__doc__) try: n = float(args['<num_rxns>']) templates_str = 'DNA' except ValueError: templates = args['<num_rxns>'].split(',') templates_str = ','.join(templates) n = len(templates) n_aliquots = int(ceil(n / 2)) s30 = MasterMix.from_text("""\ Reagent Stock Volume MM? ======= ===== ====== === water 1.2 µL yes A 10x 1 µL yes B 2.5x 4 µL yes C 3.33x 3 µL yes DNA 75 nM 0.8 µL """) s30.num_reactions = n s30['DNA'].name = templates_str protocol = Protocol() protocol += f"""\ Thaw {plural(n_aliquots):# S30 extract aliquot/s} [1]. """ protocol += f"""\ Setup the S30 extract reaction:
def parse_reaction(reaction_input): if isinstance(reaction_input, dict): return {k: MasterMix(v) for k, v in reaction_input.items()} else: return MasterMix(reaction_input)
#!/usr/bin/env python3 import stepwise from inform import plural from stepwise import Protocol, Step, Footnote, MasterMix p = Protocol() n = 6 loading_buf = MasterMix("""\ Reagent Stock Volume MM? ====================== ===== ========= === water to 5.0 µL y Bolt LDS sample buffer 4x 2.5 µL y Bolt reducing agent 10x 1.0 µL y """) loading_buf.num_reactions = 2 * n loading_buf.extra_percent = 50 protein_samples = MasterMix("""\ Reagent Stock Volume MM? ========================= ========= ========== === water to 10.0 µL y loading buffer master mix 2x 5.0 µL y BSA 500 ng/µL 1.0 µL y """) protein_samples.num_reactions = n protein_samples.extra_percent = 10 dna_samples = MasterMix("""\ Reagent Stock Volume MM?
Amplification − + + + − − + expected? """ p += f"""\ Attach HUH-tagged DNA to the dCas9 RNP. {huh} - Incubate at 37°C for 15 min. """ bal31 = MasterMix("""\ Reagent Stock Volume MM? ================ ====== ======== === water to 50 µL yes dCas9-PCV2-DNA 100 nM 10 µL NEBuffer 3.1 [2] 10x 5 µL yes BAL-31 1 U/µL 1 µL """) bal31.hold_ratios.volume = '20 µL' bal31.num_reactions = 3 p += f"""\ Setup {plural(bal31.num_reactions):# BAL-31 digestion/s} [1]: {bal31} - Incubate at 30°C for 10 min. - Add EGTA to 30 mM - Incubate at 65°C for 10 min. """