def get_protocol(self): p = stepwise.Protocol() s = ul() if self.names: p += pl( f"Purify {','.join(self.names)} by ethanol precipitation [1,2]:", s) else: p += pl("Perform an ethanol precipitation [1,2]:", s) s += f"""\ Add {self.cation_name} to {self.cation_conc}.""" s += f"""\ Add {self.carrier_name} to {self.carrier_conc}.""" s += f"""\ Add {plural(self.solvent_volume):# volume/s} {self.solvent_name} and mix well.""" s += f"""\ If necessary, divide the sample between microfuge tubes such that none holds more than 400 µL.""" if self.incubation and (t := self.incubation_time): incubation_time = "overnight" if t == 'overnight' else f"for {t}" s += f"""\
def get_protocol(self): transfer = self.volume * (f := self.inv_factor) / (1 - f) initial_volume = self.volume + transfer conc_high_str = format_quantity(self.conc_high, self.conc_unit, 'g') material_str = f'{conc_high_str} {self.material}'.lstrip() conc_table = [[i, format_quantity(conc, self.conc_unit, 'e')] for i, conc in enumerate(self.concentrations, 1)] num_tubes = self.steps if self.include_zero else self.steps - 1 each_tube = 'each tube *except the last*' if self.include_zero else 'each tube' protocol = stepwise.Protocol() protocol += pl( "Perform a serial dilution [1]:", ul( f"Put {initial_volume:.2f} μL {material_str} in a tube.", f"Put {self.volume:.2f} μL {self.diluent} in {plural(num_tubes):# adjacent tube/s}.", f"Transfer {transfer:.2f} μL between {each_tube} to make {self.steps} {self.factor:.2g}-fold dilutions.", ), ) protocol.footnotes[1] = pl( "The final concentrations will be:", pre(stepwise.tabulate(conc_table, align='>>')), br='\n', ) return protocol
def get_protocol(self): phrases = [] n = plural(self.product_tags) if self.show_product_tags: phrases.append(f"Concentrate the following {n:sample/s}") elif self.product_tags: phrases.append(f"Concentrate the {n:sample/s}") else: phrases.append("Concentrate the sample(s)") if self.volume and self.conc: err = UsageError(volume=self.volume, conc=self.conc) err.brief = "cannot specify volume and concentration" err.info += "volume: {volume}" err.info += "conc: {conc}" raise err elif self.volume: phrases.append(f"to {self.volume}") elif self.conc: phrases.append(f"to {self.conc}") else: pass if self.show_product_tags: phrases.append( f"by lyophilization: {', '.join(map(str, self.product_tags))}") else: phrases.append("by lyophilization.") return stepwise.Protocol(steps=[' '.join(phrases)], )
def get_gel_electrophoresis_steps(self): p = stepwise.Protocol() n = plural(self.samples) gel = Gel(self.gel_preset) mix = gel.sample_mix k = mix.volume / mix['sample'].volume for sample in self.samples: sample.stock_conc sample.sample_volume_per_lane_uL = min( sample.volume_uL, sample.volume_uL / ceil(sample.mass_ug / '20 µg'), mix['sample'].volume.value or inf, ) sample.load_volume_per_lane_uL = k * sample.sample_volume_per_lane_uL sample.num_lanes = int(ceil(sample.volume_uL / sample.sample_volume_per_lane_uL)) conc_vol_groups = group_by_identity( self.samples, key=lambda x: (x.stock_conc, x.volume_uL), ) for (conc, volume_uL), group in conc_vol_groups: prep_gel = Gel(self.gel_preset) prep_gel.num_samples = len(group) mix = prep_gel.sample_mix mix.hold_ratios.volume = k * volume_uL, 'µL' mix['sample'].name = ','.join(str(x.name) for x in group) mix['sample'].stock_conc = conc p += prep_gel.prep_step if x := self.gel_percent: gel.gel_percent = x
def get_protocol(self): p = stepwise.Protocol() ## Clean your bench p += stepwise.load('rnasezap') ## In vitro transcription rxn = self.reaction n = plural(rxn.num_reactions) f = self.footnotes.get('reaction', []) p += paragraph_list( f"Setup {n:# in vitro transcription reaction/s}{p.add_footnotes(*f)}:", rxn, unordered_list(*self.instructions), ) f = self.footnotes.get('incubation', []) if self.short and affected_by_short(self.incubation_times_min): f += [ f"Reaction time is different than usual because the template is short (<{self.template_length_threshold} bp)." ] p += f"Incubate at {self.incubation_temp_C}°C for {format_min(pick_by_short(self.incubation_times_min, self.short))}{p.add_footnotes(*f)}." ## DNase treatment if self.dnase: f = self.footnotes.get('dnase', []) p += paragraph_list( f"Setup {n:# DNase reaction/s}{p.add_footnotes(*f)}:", self.dnase_reaction, ) p += f"Incubate at {self.dnase_incubation_temp_C}°C for {format_min(self.dnase_incubation_time_min)}." return p
def get_gel_extraction_steps(self): p = stepwise.Protocol() names = self._cluster_names_by_molecule() desired = oxford_comma(x) if (x := self.desired_bands) else 'desired' n = plural(max(len(self.desired_bands), len(self.samples))) f = "Based on Fitzy's DNA PAGE purification protocol, [Nilson2013], and [Petrov2013]." p += pl(f"Cut the {desired} {n:band/s} out of the gel{p.add_footnotes(f)}.", ul( "Place the gel over a TLC plate.", "Use a UV light to visualize the RNA (dark spot).", "Consider visualizing remaining gel to ensure that all desired RNA was excised.", )) p += pl(f"Crush the gel {n:slice/s}.", ul( "Poke a hole in the bottom of a 0.65 mL tube with a 27 g needle.", "Place gel slice inside the 0.65 mL tube.", "Place the 0.65 mL tube inside a 1.5 mL tube.", "Spin at max speed for 5 min.", )) eb = elution_buffer() eb.hold_ratios.volume = 500 * len(self.samples), 'µL' p += pl( "Resuspend gel in 400 µL PAGE elution buffer:", eb, ) if names['RNA']: p += f"Incubate {join_if(names['RNA'], names['DNA'])}at 4°C overnight with end-over-end mixing." if names['DNA']: p += f"Incubate {join_if(names['DNA'], names['RNA'])}at 55°C overnight with 800 rpm mixing." return p
def get_stub_protocol(self): tags = [x.tag for x in self.stocks] in_diluent = f' in {self.diluent}' if self.diluent else '' p = stepwise.Protocol() p += f"Dilute {oxford_comma(tags)} to {self.target_conc}{in_diluent}." return p
def get_protocol(self): protocol = stepwise.Protocol() pcr, primer_mix = self.reaction thermocycler = self.thermocycler_protocol footnotes = [] # Primer mix (if applicable): example_uM = min(x.stock_uM for x in flatten(self.primer_pairs)) footnotes.append(pl( f"For resuspending lyophilized primers:", f"{example_uM} µM = {1e3 / example_uM:g} µL/nmol", br='\n', )) if primer_mix: protocol += pl( f"Prepare 10x primer mix{protocol.add_footnotes(*footnotes)}:", primer_mix, ) footnotes = [] # PCR reaction setup: if self.footnote: # Before the footnote on resuspending the primers, if it hasn't # been added to the protocol already. footnotes.insert(0, self.footnote) if x := pcr['template DNA'].stock_conc: footnotes.append(pl( f"For diluting template DNA to {x}:", f"Dilute 1 µL twice into {sqrt(1000/x.value):.1g}*sqrt([DNA]) µL", br='\n', ))
def __init__(self, product): args = product.maker_args self.products = [product] self.dependencies = args.get('deps', []) if isinstance(self.dependencies, str): self.dependencies = self.dependencies.split(',') if 'protocol' in args: self.protocol = stepwise.Protocol(steps=args['protocol']) # Maker attributes: if 'conc' in args: self.product_conc = stepwise.Quantity.from_string(args['conc']) if 'volume' in args: self.product_volume = stepwise.Quantity.from_string(args['volume']) # Synthesis attributes: if 'seq' in args: self.product_seqs = [args['seq']] if 'molecule' in args: self.product_molecule = args['molecule'] if 'circular' in args: self.is_product_circular = freezerbox.parse_bool(args['circular'])
def get_protocol(self): # Maybe this should be the getter function for the assembly param... p = stepwise.Protocol() rxn = self.reaction n = rxn.num_reactions n_frags = self.num_fragments f = 'https://tinyurl.com/yaa5mqz5' p += pl( f"Setup {plural(n):# Golden Gate assembl/y/ies}{p.add_footnotes(f)}:", rxn, ) if n_frags <= 2: p += pl( "Run the following thermocycler protocol:", ul("37°C for 5 min", ), "Or, to maximize the number of transformants:", ul( "37°C for 60 min", "60°C for 5 min", ), ) elif n_frags <= 4: p += pl( "Run the following thermocycler protocol:", ul( "37°C for 60 min", "60°C for 5 min", ), ) elif n_frags <= 10: p += pl( "Run the following thermocycler protocol:", ul( "Repeat 30 times:", ul( "37°C for 1 min", "16°C for 1 min", ), "60°C for 5 min", ), ) else: p += pl( "Run the following thermocycler protocol:", ul( "Repeat 30 times:", ul( "37°C for 5 min", "16°C for 5 min", ), "60°C for 5 min", ), ) return p
def get_protocol(self): anneal = AnnealMrnaLinker(self.mrnas, self.linkers) anneal.num_reactions = self.num_reactions anneal.linker_ratio = 0.6 # See expt #1 # Scale the reactions such that we'll end up with enough mRNA: anneal_rxn = anneal.reaction mrna_pmol = ( self.expected_dead_volume_uL * self.target_conc_uM / self.expected_yield ) mrna_conc_uM = anneal_rxn['mRNA'].stock_conc.value anneal.mrna_volume_uL = max( mrna_pmol / mrna_conc_uM, self.mrna_volume_uL, ) ligate = LigateMrnaLinker(anneal) wash = WashBarendt() wash.mwco_kDa = self.mwco_kDa p = stepwise.Protocol() p += anneal.protocol p += ligate.protocol if self.label: p += f"Label the product: {self.label}" if self.wash: p += wash.protocol if self.aliquot: p += stepwise.load('aliquot "4 µL" "1 µM"') return p
def get_protocol(self): self._bind_samples() p = stepwise.Protocol() p += self.gel_electrophoresis_steps p += self.gel_extraction_steps p += self.product_recovery_steps return p
def get_protocol(self): p = stepwise.Protocol() p += pl( f"Setup {plural(self.num_reactions):# ligation reaction/s}:", self.reaction, ) p += "Incubate at room temperature for 1h." return p
def test_to_stdout(capsysbinary): unpickleable_protocol = stepwise.Protocol(steps=[lambda: None]) io = stepwise.ProtocolIO(unpickleable_protocol) io.to_stdout() cap = capsysbinary.readouterr() io_out = pickle.loads(cap.out) assert io_out.protocol == '' assert io_out.errors == 1 assert "AttributeError: Can't pickle local object" in cap.err.decode()
def __init__(self, products): from more_itertools import flatten steps = list( flatten(x.maker_args.get('protocol', []) for x in products)) deps = list(flatten(x.maker_args.get('deps', []) for x in products)) self.products = products self.protocol = stepwise.Protocol(steps=steps) self.dependencies = deps
def get_protocol(self): p = stepwise.Protocol() if self.sample_mix: p += self.prep_step p += self.run_step if self.stain: p += stepwise.load(self.stain) return p
def get_protocol(self): optics = [self.parse_optics(x) for x in self.optics] lasers = [f"{plural(optics):laser/s}:" ] + [f"{x['laser']} nm" for x in optics] filters = [f"{plural(optics):filter/s}:" ] + [x['filter'] for x in optics] p = stepwise.Protocol() p += pl( "Image with a laser scanner:", table([lasers, filters], align='<>>'), ) return p
def get_protocol(self): p = stepwise.Protocol() rxn = self.reaction p += pl( f"Setup {plural(self.num_reactions):# {self.title} reaction/s}{p.add_footnotes(self.setup_footnote)}:", rxn, ul(*self.setup_instructions), ) if self.incubation_time != '0': p += f"Incubate at {self.incubation_temp_C:g}°C for {self.incubation_time}{p.add_footnotes(self.incubation_footnote)}." return p
def get_protocol(self): p = stepwise.Protocol() rxn = self.reaction n = rxn.num_reactions f = "https://tinyurl.com/ychbvkra" p += pl( f"Setup {plural(n):# Gibson assembl/y/ies}{p.add_footnotes(f)}:", rxn, ) incubation_time = '15 min' if self.num_fragments <= 3 else '1h' p += f"Incubate at 50°C for {incubation_time}." return p
def get_protocol(self): p = stepwise.Protocol() pl = stepwise.paragraph_list() ul = stepwise.unordered_list() def break_if_too_long(pl, ul, n=4): if len(ul) > n: ul = stepwise.unordered_list() pl += ul return ul footnotes = [] if self.protocol_link: footnotes.append(self.protocol_link) if self.column_capacity_ug: footnotes.append(f"Column capacity: {self.column_capacity_ug} µg") if self.product_tags and self.show_product_tags: product_tags = oxford_comma(self.product_tags) + ' ' else: product_tags = '' p += pl pl += f"Purify {product_tags}using {self.protocol_name}{p.add_footnotes(*footnotes)}:" pl += ul if self.spin_speed_g: ul += f"Perform all spin steps at {self.spin_speed_g}g." ## Dilute if x := self.target_sample_volume_uL: v = self.sample_volume_uL if not isinstance(x, dict): target = f'{x} µL' skip = v and v == x self.sample_volume_uL = x elif 'min' in x and 'max' in x: target = f"between {x['min']}–{x['max']} µL" skip = v and x['min'] <= v <= x['max'] elif 'min' in x: target = f"at least {x['min']} µL" skip = v and x['min'] <= v elif 'max' in x: target = f"at most {x['max']} µL" skip = v and v <= x['max'] if not skip: ul += f"Ensure that the sample is {target}."
def get_protocol(self): p = stepwise.Protocol() p += pl( "Remove unligated linker by ultrafiltration:", s := ul( "Bring reaction to 500 µL with 8M urea.", f"Load onto a {self.mwco_kDa} kDa MWCO spin-filter [1].", "Spin 14000g, 15 min.", "Wash with 500 µL 8M urea.", "Wash with 500 µL nuclease-free water.", "Wash with water again.", "Wash with water again, but spin for 30 min.", "Invert the filter into a clean tube and spin 1000g, 2 min to collect ligated product in a volume of ≈15 µL.", ), )
def get_protocol(self): Q = Quantity.from_string if self.conc: aliquot_info = f'{Q(self.volume)}, {Q(self.conc)}' else: aliquot_info = f'{Q(self.volume)}' if self.product_tags and self.show_product_tags: product_tags = f" of: {', '.join(self.product_tags)}" else: product_tags = "." return stepwise.Protocol( steps=[f"Make {aliquot_info} aliquots{product_tags}"], )
def get_protocol(self): p = stepwise.Protocol() rxn = self.reaction p += pl( f"Setup {plural(rxn.num_reactions):# ligation reaction/s}{p.add_footnotes('https://tinyurl.com/y7gxfv5m')}:", rxn, ) p += pl( "Incubate at the following temperatures:", ul( "25°C for 15 min", "65°C for 10 min", ), ) return p
def get_protocol(self): protocol = stepwise.Protocol() n = self.num_reactions protocol += f"""\ Setup {plural(n):# annealing reaction/s}: {self.reaction} """ protocol += f"""\ Perform the {plural(n):annealing reaction/s}: - Incubate at 95°C for 2 min. - Cool at room temperature. """ return protocol
def get_protocol(self): p = stepwise.Protocol() rxn = self.reaction rxn_name = 'ligation' if self.use_ligase else 'negative control' n = rxn.num_reactions p += stepwise.pl( f"Setup {plural(n):# {rxn_name} reaction/s}:", rxn, ) if self.incubate: p += pl( f"Incubate the {plural(n):ligation reaction/s} as follows:", s := ul( f"{self.incubate_temp} for {self.incubate_time}." ), ) if self.quench:
def get_product_recovery_steps(self): p = stepwise.Protocol() names = self._cluster_names_by_molecule() # Filter material: # - Corning has a good guide on which material to select: # https://www.corning.com/catalog/cls/documents/selection-guides/t_filterselectionguide.pdf # # - I want 0.22 µm, because that's the standard size for filter # sterilizing biological buffers (that's not my application here, but # I can see myself wanting to do that). # # - I want cellulose acetate filters. Nylon and cellulose nitrate have # high DNA binding, which will cause me to lose material. The # downside to cellulose acetate is that it has a wetting agent that # will end up in the sample. However, this will be removed by the # Zymo column in the subsequent step. # # - Product number: 8161 (non sterile) # # Centrifugation speed: # - Fitzy's DNA PAGE purification protocol calls for 4 min at 7000 rpm # - The Corning guide (see above) includes an agarose gel purification # protocol, which calls for 13,000g for 5-20 min. But this protocol # has no incubation step, so I gather that the spin is supposed to # pull the solvent out of the gel. I probably don't need to go so # fast, but why not go as fast as the columns can tolerate? f = "Nylon and cellulose nitrate have high DNA-binding: https://tinyurl.com/3pkyc8dr" p += pl( "Remove gel debris by spin filtration:", ul( f"Load samples onto a 0.22 µm cellose-acetate Spin-X column{p.add_footnotes(f)}.", "Spin at 13,000g for 5 min." ), ) if self.cleanup: if names['RNA']: p += cleanup(self.rna_cleanup_preset, names['RNA'], names['DNA']) if names['DNA']: p += cleanup(self.dna_cleanup_preset, names['DNA'], names['RNA']) return p
def get_run_step(self): p = stepwise.Protocol() additive = f" with {x}" if (x := self.gel_additive) else "" percent = x.replace('-', '–') if isinstance(x := self.gel_percent, str) else x p += pl( f"Run a gel{p.add_footnotes(self.protocol_link)}:", dl( ("gel", f"{percent}% {self.gel_type}{additive}"), ("buffer", f"{self.gel_buffer}"), ("ladder", self.ladder_name and f"{self.ladder_volume_uL:g} µL {self.ladder_name}"), ("samples", self.load_volume_uL and f"{self.load_volume_uL:.3g} µL/lane"), ("prerun", self.prerun_time_min and f"{self.prerun_volts:g}V for {self.prerun_time_min:g} min"), ("run", f"{self.run_volts:g}V for {self.run_time_min:g} min"), )) return p
def get_protocol(self): protocol = stepwise.Protocol() targets = iter_targets( self.db, self.tags, include_deps=self.include_deps, ) for key, group in group_by_synthesis(targets): for maker in iter_makers(self.db, key, group): protocol += maker.protocol if getattr(maker, 'label_products', True): protocol += label_products(maker.products) parents = [x.parent for x in group] for key, subgroup in group_by_cleanup(parents): for maker in iter_makers(self.db, key, subgroup): protocol += maker.protocol return protocol
def get_protocol(self): p = stepwise.Protocol() rxn = self.reaction p += f"""\ Setup {plural(self.num_reactions):# NEBExpress reaction/s} [1]: {rxn} - Thaw all components on ice. - Mix the S30 extract and protein synthesis buffer by gently vortexing. """ p += f"""\ Incubate at {self.incubation_temp_C}°C for {self.incubation_time} [4]. """ p.footnotes[1] = """\ During the experimental setup, it is recommended to add the linear DNA template in the last step to allow GamS to bind and inhibit RecBCD exonuclease before RecBCD has a chance to act on the DNA. """ p.footnotes[2] = """\ Aliquot to avoid multiple freeze/thaw cycles. """ p.footnotes[3] = """\ Optimal concentration must be determined empirically for each template. """ p.footnotes[4] = """\ Additional incubation time (maximum 10 hours) at 37°C may increase yield. """ return p
def get_protocol(self): p = stepwise.Protocol() rxn = self.reaction n = rxn.num_reactions p += pl( f"Setup {plural(n):# annealing reaction/s} [1]:", rxn, ) p.footnotes[1] = """\ Using 0.6x linker reduces the amount of unligated linker, see expt #1.""" p += pl( f"Perform the {plural(n):annealing reaction/s}:", ul( "Incubate at 95°C for 2 min.", "Cool at room temperature.", ), ) return p