Source code for dnacauldron.Assembly.builtin_assembly_classes.BioBrickStandardAssembly

# from copy import copy
# from ...biotools import set_record_topology
# from ...biotools import annotate_record
from ..Assembly import Assembly
from ...AssemblyMix import RestrictionLigationMix
from ..AssemblySimulation import AssemblySimulation
from ..AssemblyFlaw import AssemblyFlaw


[docs]class BioBrickStandardAssembly(Assembly): """Representation and simulation of the Biobrick 2-part assembly standard. Parameters ---------- parts A list of parts names corresponding to records in a repository. There must be exactly 2 parts and they must be represented on a backbone (i.e. circular constructs), and the first part will be inserted in the backbone of the second part, upstream of the second part. name Name of the assembly as it will appear in reports. max_constructs None or a number of maximum assemblies to compute (avoids complete freeze for combinatorial assemblies with extremely many possibilities). expected_constructs Either a number or a string ``'any_number'``. If the number of constructs doesn't match this value, the assembly will be considered invalid in reports and summaries connectors_collection Name of a collection in the repository from which to get candidates for connector autocompletion. dependencies (do not use). Metadata indicating which assemblies depend on this assembly, or are depended on by it. """ def __init__( self, parts, name="unnamed_assembly", connectors_collection=None, expected_constructs=1, max_constructs=40, dependencies=None, ): Assembly.__init__( self, name=name, parts=parts, max_constructs=max_constructs, dependencies=dependencies, ) self.connectors_collection = connectors_collection self.expected_constructs = expected_constructs self.enzymes = ["EcoRI", "SpeI", "XbaI"] self.extra_construct_data = dict(enzymes=self.enzymes)
[docs] def simulate(self, sequence_repository, annotate_parts_homologies=True): """Simulate the assembly, return an AssemblySimulation.""" if len(self.parts) != 2: error = AssemblyFlaw( assembly=self, message="BioBrick Std Assembly requires 2 parts exactly.", suggestion="Check assembly plan", data={"parts": len(self.parts)}, ) AssemblySimulation( assembly=self, sequence_repository=sequence_repository, errors=[error], ) left_part, right_part = sequence_repository.get_records(self.parts) errors, mixes = [], [] # E+S MIX TO DIGEST THE LEFT PART (INSERT) mix_1 = RestrictionLigationMix( parts=[left_part], enzymes=["EcoRI", "SpeI"], name=left_part.id + "_E+S_restriction", ) mixes.append(mix_1) inserts = [ fragment for fragment in mix_1.fragments + mix_1.reverse_fragments if fragment.seq.ends_tuple() == ("AATT", "CTAG") and not fragment.is_reversed ] if len(inserts) != 1: prefix = "No" if len(inserts) == 0 else "Multiple" error = AssemblyFlaw( assembly=self, message=prefix + " AATT-CTAG fragments in E+S digestion.", suggestion=( "Check EcoRI/SpeI sites in %s. Also beware that the E+S " "part should appear in direct sense in its record." ) % left_part.id, data={"parts": len(self.parts)}, ) errors.append(error) # E+X MIX TO DIGEST THE RIGHT PART (BACKBONE) mix_2 = RestrictionLigationMix( parts=[right_part], enzymes=["EcoRI", "XbaI"], name=right_part.id + "_E+X_restriction", ) mixes.append(mix_2) backbones = [ fragment for fragment in mix_2.fragments + mix_2.reverse_fragments if fragment.seq.ends_tuple() == ("CTAG", "AATT") and len(fragment) > 100 ] if len(backbones) != 1: prefix = "No" if len(backbones) == 0 else "Multiple" error = AssemblyFlaw( assembly=self, message=prefix + " left-CTAG overhang found in E+X mix.", suggestion="Check EcoRI/XbaI sites in %s" % right_part.id, data={"parts": len(self.parts)}, ) errors.append(error) if len(errors): return AssemblySimulation( assembly=self, errors=errors, mixes=mixes, sequence_repository=sequence_repository, ) # FINAL ASSEMBLY MIX insert = inserts[0] backbone = backbones[0] mix = RestrictionLigationMix( fragments=[insert, backbone], name="assembly_mix" ) mixes.append(mix) final_record = insert.assemble_with(backbone).circularized() final_record.id = self.name final_record.fragments = [insert, backbone] return AssemblySimulation( assembly=self, construct_records=[final_record], mixes=mixes, errors=errors, sequence_repository=sequence_repository, )
# def fragments_set_filter(fragments): # if len(fragments) != 2: # return False # f1, f2 = fragments # uses_both_parts = f1.original_part.id != f2.original_part.id # return uses_both_parts and not f1.is_reversed # generator = mix.compute_circular_assemblies( # annotate_parts_homologies=annotate_parts_homologies, # fragments_sets_filters=(fragments_set_filter,), # ) # construct_records = sorted( # [asm for (i, asm) in zip(range(self.max_constructs), generator)], # key=lambda asm: str(asm.seq), # ) # self.attribute_ids_to_constructs(construct_records) # n_constructs = len(construct_records) # if n_constructs != 1: # error = AssemblyFlaw( # assembly=self, # message="Found %d constructs instead of 1." % n_constructs, # suggestion="Hmmmm", # ) # errors.append(error) # return AssemblySimulation( # assembly=self, # construct_records=construct_records, # mixes=mixes, # errors=errors, # sequence_repository=sequence_repository, # )