def test_create(self): sbol3.set_namespace('https://github.com/synbiodex/pysbol3') instance_of = sbol3.Component('comp1', sbol3.SBO_DNA) sc1 = sbol3.SubComponent(instance_of) self.assertIsNotNone(sc1) self.assertEqual(instance_of.identity, sc1.instance_of) sc2 = sbol3.SubComponent(instance_of.identity) self.assertEqual(instance_of.identity, sc2.instance_of)
def test_cloning_with_children(self): # This test does not use `sbol3.set_namespace` as the other # cloning unit tests do. This is on purpose to verify that # cloning does not rely on the default namespace. doc = sbol3.Document() namespace = 'https://github.com/synbiodex/pysbol3' c1_identity = posixpath.join(namespace, 'c1') c2_identity = posixpath.join(namespace, 'c2') s1_identity = posixpath.join(namespace, 's1') c1 = sbol3.Component(c1_identity, sbol3.SBO_DNA) doc.add(c1) seq1 = sbol3.Sequence(s1_identity) doc.add(seq1) c1.sequences.append(seq1) sc1 = sbol3.SubComponent(c1) es1 = sbol3.EntireSequence(seq1) sc1.source_locations.append(es1) c1.features = [sc1] c2 = c1.clone(c2_identity) self.assertEqual(c2_identity, c2.identity) self.assertIsNone(c2.document) # Check on the SubComponent sc2 = c2.features[0] self.assertIsInstance(sc2, sbol3.SubComponent) self.assertNotEqual(sc1.identity, sc2.identity) self.assertTrue(sc2.identity.startswith(c2.identity)) # Ensure that the reference was updated properly self.assertEqual(c2.identity, sc2.instance_of) self.assertIsNone(sc2.document) es2 = sc2.source_locations[0] self.assertIsInstance(es2, sbol3.EntireSequence) self.assertNotEqual(es1.identity, es2.identity) self.assertTrue(es2.identity.startswith(c2.identity)) self.assertEqual(es1.sequence, es2.sequence) self.assertIsNone(es2.document)
def test_copy_stability(self): # Test the stability of naming of objects across copies. # See https://github.com/SynBioDex/pySBOL3/issues/231 # # Strategy: create an object with 10+ children of the same # type. Add to a document and serialize the document. Load the # serialized document. Copy the object to a new document. # Serialize the new document. Compare the serializations. If we # use sorted ntriples, the serializations should be the same. # This will demonstrate that we maintain names properly despite # the inherently unordered nature of SBOL. sbol3.set_namespace('https://github.com/synbiodex/pysbol3') c1 = sbol3.Component('c1', types=[sbol3.SBO_DNA]) # Create a double-digit number of children to test sort of 10, 11, 1, etc. for i in range(12): instance_of_uri = f'https://example.com/instance/i{i}' c1.features.append(sbol3.SubComponent(instance_of=instance_of_uri)) doc1 = sbol3.Document() doc1.add(c1) # Serialize to string doc1_string = doc1.write_string(sbol3.SORTED_NTRIPLES) self.assertIsNotNone(doc1_string) # Load the serialized document into a new document tmp_doc = sbol3.Document() tmp_doc.read_string(doc1_string, sbol3.SORTED_NTRIPLES) # Locate the top level to copy tmp_c1 = tmp_doc.find('c1') self.assertIsNotNone(tmp_c1) self.assertIsInstance(tmp_c1, sbol3.TopLevel) # Copy the top level into a new document doc2 = sbol3.Document() sbol3.copy([tmp_c1], into_document=doc2) doc2_string = doc2.write_string(sbol3.SORTED_NTRIPLES) # Verify that the serializations are identical self.assertEqual(doc1_string, doc2_string)
def test_shacl_closure_with_child_objects(self): # See https://github.com/SynBioDex/pySBOL3/issues/348 # See https://github.com/SynBioDex/pySBOL3/issues/353 sbol3.set_namespace('https://github.com/SynBioDex/pySBOL3') doc = sbol3.Document() c_top = sbol3.Component('top', sbol3.SBO_DNA) c_middle = sbol3.Component('middle', sbol3.SBO_DNA) c_bottom = sbol3.Component('bottom', sbol3.SBO_DNA) subc_middle = sbol3.SubComponent(c_middle) c_top.features = [subc_middle] subc_bottom = sbol3.SubComponent(c_bottom) c_middle.features = [subc_bottom] subc_bottom_ref = sbol3.ComponentReference(in_child_of=subc_middle, refers_to=subc_bottom) c_top.features.append(subc_bottom_ref) doc.add(c_top) self.assertFalse(len(doc.validate()))
def test_no_identity_exception(self): # See https://github.com/SynBioDex/pySBOL3/issues/357 sbol3.set_namespace('https://github.com/SynBioDex/pySBOL3') collection = sbol3.Collection('foo_collection') subc = sbol3.SubComponent( instance_of='https://github.com/SynBioDex/pySBOL3/c1') exc_regex = r'Object identity is uninitialized\.$' with self.assertRaisesRegex(ValueError, exc_regex): collection.members.append(subc)
def test_copy_child_objects(self): sbol3.set_namespace('https://github.com/synbiodex/pysbol3') doc = sbol3.Document() root = sbol3.Component('root', sbol3.SBO_DNA) sub1 = sbol3.Component('sub1', sbol3.SBO_DNA) sub2 = sbol3.Component('sub2', sbol3.SBO_DNA) sc1 = sbol3.SubComponent(sub1) sc2 = sbol3.SubComponent(sub2) root.features.append(sc1) root.features.append(sc2) doc.add(root) doc.add(sub1) doc.add(sub2) doc2 = sbol3.Document() root_copy = root.copy(target_doc=doc2) self.assertEqual([sc.identity for sc in root.features], [sc.identity for sc in root_copy.features])
def test_external_instance_of(self): # See https://github.com/SynBioDex/pySBOL3/issues/136 c_uri = 'https://synbiohub.example.org/component1' m9_media = 'https://synbiohub.example.org/m9-media' e_coli = 'https://synbiohub.example.org/e-coli-DH5-alpha' c = sbol3.Component(c_uri, sbol3.SBO_DNA) sc1 = sbol3.SubComponent(m9_media) sc2 = sbol3.SubComponent(e_coli) c.features = [sc1, sc2] self.assertEqual(len(c.features), 2) doc1 = sbol3.Document() doc1.add(c) doc2 = sbol3.Document() doc2.read_string(doc1.write_string(sbol3.NTRIPLES), sbol3.NTRIPLES) c2 = doc2.find(c_uri) self.assertIsNotNone(c2) self.assertEqual(2, len(c2.features)) self.assertCountEqual([m9_media, e_coli], [sc.instance_of for sc in c2.features])
def test_shacl_closure_simple(self): # This is a very small test case to reproduce the issue at the # center of https://github.com/SynBioDex/pySBOL3/issues/348 sbol3.set_namespace('https://github.com/SynBioDex/pySBOL3') other_component = 'https://github.com/SynBioDex/pySBOL3/other_c' sc = sbol3.SubComponent(instance_of=other_component) c = sbol3.Component('c1', types=[sbol3.SBO_DNA], features=[sc]) doc = sbol3.Document() doc.add(c) report = doc.validate() self.assertEqual(0, len(report))
def add_feature( component: sbol3.Component, to_add: Union[sbol3.Feature, sbol3.Component]) -> sbol3.Feature: """Pass-through adder for adding a Feature to a Component for allowing slightly more compact code. Note that unlike ensure_singleton_feature, this allows adding multiple instances :param component: Component to add the Feature to :param to_add: Feature or Component to be added to system. Components will be wrapped in a SubComponent Feature :return: feature added (SubComponent if to_add was a Component) """ if isinstance(to_add, sbol3.Component): to_add = sbol3.SubComponent(to_add) component.features.append(to_add) return to_add
def test_list_wrapping(self): # Ensure that at least certain properties handle automatic list # wrapping and are typed to do so. # See https://github.com/SynBioDex/pySBOL3/issues/301 sbol3.set_namespace('https://github.com/synbiodex/pysbol3') instance_uri = 'https://example.org/instance' seq1 = sbol3.Sequence('seq1') test_loc = sbol3.EntireSequence(seq1) seq2 = sbol3.Sequence('seq2') test_source_loc = sbol3.EntireSequence(seq1) subcomp1 = sbol3.SubComponent(instance_of=instance_uri, locations=test_loc, source_locations=test_source_loc) self.assertEqual([test_loc], subcomp1.locations) self.assertEqual([test_source_loc], subcomp1.source_locations)
def make_combinatorial_derivation(document, display_id, part_lists, reverse_complements, constraints): # Make the combinatorial derivation and its template template = sbol3.Component(display_id + "_template", sbol3.SBO_DNA) document.add(template) cd = sbol3.CombinatorialDerivation(display_id, template) cd.strategy = sbol3.SBOL_ENUMERATE # for each part, make a SubComponent or LocalSubComponent in the template and link them together in sequence template_part_list = [] for part_list, rc in zip(part_lists, reverse_complements): # it's a variable if there are multiple values or if there's a single value that's a combinatorial derivation if len(part_list) > 1 or not isinstance(part_list[0], sbol3.Component): sub = sbol3.LocalSubComponent({sbol3.SBO_DNA }) # make a template variable sub.name = "Part " + str(len(template_part_list) + 1) template.features.append(sub) var = sbol3.VariableFeature(cardinality=sbol3.SBOL_ONE, variable=sub) cd.variable_features.append(var) # add all of the parts as variables for part in part_list: if isinstance(part, sbol3.Component): var.variants.append(part) elif isinstance(part, sbol3.CombinatorialDerivation): var.variant_derivations.append(part) else: raise ValueError( "Don't know how to make library element for " + part.name + ", a " + str(part)) else: # otherwise it's a fixed element of the template sub = sbol3.SubComponent(part_list[0]) template.features.append(sub) # in either case, orient and order the template elements sub.orientation = (sbol3.SBOL_REVERSE_COMPLEMENT if rc else sbol3.SBOL_INLINE) if template_part_list: template.constraints.append( sbol3.Constraint(sbol3.SBOL_MEETS, template_part_list[-1], sub)) template_part_list.append(sub) # next, add all of the constraints to the template #template.constraints = (make_constraint(c.strip(),template_part_list) for c in (constraints.split(',') if constraints else [])) # impacted by pySBOL3 appending c_list = (make_constraint(c.strip(), template_part_list) for c in (constraints.split(',') if constraints else [])) for c in c_list: template.constraints.append(c) # return the completed part return cd
def make_composite_component(display_id, part_lists, reverse_complements): # Make the composite as an engineered region composite_part = sbol3.Component(display_id, sbol3.SBO_DNA) composite_part.roles.append(sbol3.SO_ENGINEERED_REGION) # for each part, make a SubComponent and link them together in sequence last_sub = None for part_list, rc in zip(part_lists, reverse_complements): if not len(part_list) == 1: raise ValueError( f'Part list should have precisely one element, but is {part_list}' ) sub = sbol3.SubComponent(part_list[0]) sub.orientation = (sbol3.SBOL_REVERSE_COMPLEMENT if rc else sbol3.SBOL_INLINE) composite_part.features.append(sub) if last_sub: composite_part.constraints.append( sbol3.Constraint(sbol3.SBOL_MEETS, last_sub, sub)) last_sub = sub # return the completed part return composite_part
def to_sbol(self, sbol_doc: sbol3.Document = None) -> sbol3.Document: """Convert the genetic network to SBOL. :param sbol_doc: The SBOL document to add the genetic network to. """ if sbol_doc: doc=sbol_doc else: print('No SBOL Document provided') print('Generating a new SBOL Document') doc = sbol3.Document() products = set() geneticnetwork = sbol3.Component('geneticnetwork', sbol3.SBO_DNA) geneticnetwork.roles.append(sbol3.SO_ENGINEERED_REGION) loica_set = set() for op in self.operators: # Operator Component operator_comp = op.sbol_comp operator_sc = sbol3.SubComponent(operator_comp) # GeneProduct Outputs Component output_str = '' output_scs = [] if type(op.output) != list: outputs = [op.output] else: outputs = op.output for op_output in outputs: output_comp = op_output.sbol_comp output_scs.append(sbol3.SubComponent(output_comp)) output_str += f'_{op_output.name}' # TODO output string for policistronic operators # TU Component if type(op)==Source: input_str= 'c' tu = sbol3.Component(f'TU_{input_str}_{op}{output_str}', sbol3.SBO_DNA) #generalize to multi input/output TUs tu.roles.append(sbol3.SO_ENGINEERED_REGION) tu.features = [operator_sc] for sc in output_scs: tu.features.append(sc) elif type(op)==Hill2: # type(op.input)==List: input_str = '' for inp in op.input: input_str += f'_{inp.name}' tu = sbol3.Component(f'TU{input_str}_{op}{output_str}', sbol3.SBO_DNA) #generalize to multi input/output TUs tu.features = [operator_sc] for sc in output_scs: tu.features.append(sc) for inp in op.input: input_comp = inp.sbol_comp if type(input_comp)==sbol3.Component: input_sc = sbol3.SubComponent(input_comp) tu.features.append(input_sc) else: tu.features.append(input_comp) else: input_str= f'_{op.input.name}' tu = sbol3.Component(f'TU{input_str}_{op}{output_str}', sbol3.SBO_DNA) #generalize to multi input/output TUs tu.features = [operator_sc] for sc in output_scs: tu.features.append(sc) input_comp = op.input.sbol_comp if type(input_comp)==sbol3.Component: input_sc = sbol3.SubComponent(input_comp) tu.features.append(input_sc) else: tu.features.append(input_comp) tu.roles.append(sbol3.SO_ENGINEERED_REGION) for i in range(len(tu.features)-1): constraint = sbol3.Constraint(sbol3.SBOL_PRECEDES, tu.features[i], tu.features[i + 1]) tu.constraints = [constraint] #tu.constraints = [sbol3.Constraint(sbol3.SBOL_PRECEDES, operator_sc, output_sc)] # generate a sequence for the TU assuming assembly by type IIS REsnf both parts will have the fusion sites. # compare last 4 bp with thefirst 4 bp of the next part, given the preceds constraint. # if they are the same then delete one of them and concatenate the rest. # else error or comment TU sequence can not be generated, provide ways to add it. # Output GeneProduct Component for op_output, sc in zip(outputs, output_scs): #make list of tuples? for output_participation if type(op_output)==Regulator: if op_output.type_ == 'PRO': output_gp_comp = sbol3.Component(f'{op_output.name}_protein', sbol3.SBO_PROTEIN) output_gp_comp.roles.append(sbol3.SO_TRANSCRIPTION_FACTOR) elif op_output.type_ == 'RNA': output_gp_comp = sbol3.Component(f'{op_output.name}_rna', sbol3.SBO_RNA) output_gp_comp.roles.append(sbol3.SO_TRANSCRIPTION_FACTOR) else: print('Unsupported output molecule type') elif type(op_output)==Reporter: # For now just support fluorescent reporters if op_output.type_ == 'PRO': output_gp_comp = sbol3.Component(f'{op_output.name}_protein', sbol3.SBO_PROTEIN) output_gp_comp.roles.append('http://purl.obolibrary.org/obo/NCIT_C37894') elif op_output.type_ == 'RNA': output_gp_comp = sbol3.Component(f'{op_output.name}_rna', sbol3.SBO_RNA) output_gp_comp.roles.append('http://purl.obolibrary.org/obo/NCIT_C37894') else: print('Unsupported output molecule type') else: print('Unsupported output Type') output_gp_sc = sbol3.SubComponent(output_gp_comp) tu.features.append(output_gp_sc) if op_output not in products: products.add(op_output) loica_set.add(output_gp_comp) # Genetic Production Interaction pf the output output_participation = sbol3.Participation(roles=[sbol3.SBO_TEMPLATE], participant=sc) gp_participation = sbol3.Participation(roles=[sbol3.SBO_PRODUCT], participant=output_gp_sc) production = sbol3.Interaction(types=[sbol3.SBO_GENETIC_PRODUCTION], participations=[output_participation, gp_participation]) tu.interactions.append(production) # obtain TU subcomponents sequences, specially CDS and flanking parts sequences # look for ATG on the CDS and upstream part sequences (in the case of MoClo the ATG is in the fusion sites) # look for stop codons on frame with the ATG. # add translated the sequence between the ATG and the stop codon as protein sequence. #protein.sequence = tu.cds.sequence # Input Product Component if type(op) == Source: inputs=[] elif type(op) == Hill2: #type(op.input) != List: inputs = op.input else: inputs = [op.input] #inputs_prod_sc = [] for op_input in inputs: if type(op_input)==Regulator: if op_input.type_ == 'PRO': input_prod_comp = sbol3.Component(f'{op_input.name}_protein', sbol3.SBO_PROTEIN) input_prod_comp.roles.append(sbol3.SO_TRANSCRIPTION_FACTOR) elif op_input.type_ == 'RNA': input_prod_comp = sbol3.Component(f'{op_input.name}_rna', sbol3.SBO_RNA) input_prod_comp.roles.append(sbol3.SO_TRANSCRIPTION_FACTOR) else: print('Unsupported input molecule type') elif type(op_input)==Supplement: input_prod_comp = sbol3.Component(f'{op_input.name}_chemical', sbol3.SBO_SIMPLE_CHEMICAL) input_prod_comp.roles.append(sbol3.SO_TRANSCRIPTION_FACTOR) else: print('Unsupported input Type') # adds two times prod comp on the repressilator but necessary for normal circuits if op_input not in products: products.add(op_input) loica_set.add(input_prod_comp) input_prod_sc = sbol3.SubComponent(input_prod_comp) tu.features.append(input_prod_sc) #inputs_prod_sc.append(input_prod_sc) #how can I not create 2 times the same component? if type(op_input)!=Regulator: # if it is a regulator it is already created loica_set.add(input_prod_comp) # Input Interaction if type(op)==Hill1 and op.alpha[0]>op.alpha[1]: input_participation = sbol3.Participation(roles=[sbol3.SBO_INHIBITOR], participant=input_prod_sc) op_participation = sbol3.Participation(roles=[sbol3.SBO_INHIBITED], participant=operator_sc) interaction = sbol3.Interaction(types=[sbol3.SBO_INHIBITION], participations=[input_participation, op_participation]) tu.interactions.append(interaction) elif type(op)==Hill2 and op.alpha[0]== max(op.alpha): input_participation = sbol3.Participation(roles=[sbol3.SBO_INHIBITOR], participant=input_prod_sc) op_participation = sbol3.Participation(roles=[sbol3.SBO_INHIBITED], participant=operator_sc) interaction = sbol3.Interaction(types=[sbol3.SBO_INHIBITION], participations=[input_participation, op_participation]) tu.interactions.append(interaction) elif type(op)==Receiver: input_participation = sbol3.Participation(roles=[sbol3.SBO_STIMULATOR], participant=input_prod_sc) op_participation = sbol3.Participation(roles=[sbol3.SBO_STIMULATED], participant=operator_sc) interaction = sbol3.Interaction(types=[sbol3.SBO_STIMULATION], participations=[input_participation, op_participation]) tu.interactions.append(interaction) elif type(op)==Hill1 and op.alpha[0]<op.alpha[1]: input_participation = sbol3.Participation(roles=[sbol3.SBO_STIMULATOR], participant=input_prod_sc) op_participation = sbol3.Participation(roles=[sbol3.SBO_STIMULATED], participant=operator_sc) interaction = sbol3.Interaction(types=[sbol3.SBO_STIMULATION], participations=[input_participation, op_participation]) tu.interactions.append(interaction) elif type(op)==Source: pass else: print('Unsupported operator Type') # Model #model_string = str(op.__dict__) op_model = sbol3.Model(f'LOICA{input_str}_{op}{output_str}_model', source='https://github.com/SynBioUC/LOICA/blob/master/loica/operators', language='http://identifiers.org/EDAM:format_3996', framework='http://identifiers.org/SBO:0000062',) #attachments=[model_string]) doc.add(op_model) tu.models.append(op_model) doc.add(tu) tu_sc = sbol3.SubComponent(tu) geneticnetwork.features.append(tu_sc) loica_list = list(loica_set) doc.add(loica_list) if len(geneticnetwork.features) > 1: for i in range(len(geneticnetwork.features)-1): geneticnetwork.constraints = [sbol3.Constraint(sbol3.SBOL_PRECEDES, geneticnetwork.features[i], geneticnetwork.features[i+1])] else: pass doc.add(geneticnetwork) return doc
def make_composite_part(document, row, composite_parts, linear_products, final_products, config): """ Create a composite part from a row in the composites sheet :param document: Document to add parts to :param row: Excel row to be processed :param composite_parts: collection of parts to add to :param linear_products: collection of linear parts to add to :param final_products: collection of final parts to add to :param config: dictionary of sheet parsing configuration variables """ # Parse material from sheet row name = row[config['composite_name_col']].value if name is None: return # skip lines without names else: name = name.strip() # make sure we're discarding whitespace display_id = sbol3.string_to_display_id(name) design_notes = (row[config['composite_notes_col']].value if row[config['composite_notes_col']].value else "") description = \ (row[config['composite_description_col']].value if row[config['composite_description_col']].value else "") final_product = row[config['composite_final_col']].value # boolean transformed_strain = row[config['composite_strain_col']].value if config[ 'composite_strain_col'] else None backbone_or_locus_raw = row[ config['composite_context_col']].value if config[ 'composite_context_col'] else None backbone_or_locus = part_names( backbone_or_locus_raw) if backbone_or_locus_raw else [] constraints = row[config['composite_constraints_col']].value if config[ 'composite_constraints_col'] else None reverse_complements = [ is_RC(spec) for spec in part_specifications(row, config) ] part_lists = \ [[partname_to_part(document, name) for name in part_names(spec)] for spec in part_specifications(row, config)] combinatorial = any( x for x in part_lists if len(x) > 1 or isinstance(x[0], sbol3.CombinatorialDerivation)) # Build the composite logging.debug( f'Creating {"library" if combinatorial else "composite part"} "{name}"' ) linear_dna_display_id = (f'{display_id}_ins' if backbone_or_locus else display_id) if combinatorial: composite_part = make_combinatorial_derivation(document, linear_dna_display_id, part_lists, reverse_complements, constraints) else: composite_part = make_composite_component(linear_dna_display_id, part_lists, reverse_complements) composite_part.name = (f'{name} insert' if backbone_or_locus else name) composite_part.description = f'{design_notes}\n{description}'.strip() # add the component to the appropriate collections document.add(composite_part) composite_parts.members.append(composite_part.identity) if final_product: linear_products.members.append(composite_part.identity) ############### # Consider strain and locus information if transformed_strain: warnings.warn("Not yet handling strain information: " + transformed_strain) if backbone_or_locus: # TODO: handle integration locuses as well as plasmid backbones backbones = [ partname_to_part(document, name) for name in backbone_or_locus ] if any(b is None for b in backbones): raise ValueError( f'Could not find specified backbone(s) "{backbone_or_locus}"') if any(not is_plasmid(b) for b in backbones): raise ValueError( f'Specified backbones "{backbone_or_locus}" are not all plasmids' ) if combinatorial: logging.debug( f"Embedding library '{composite_part.name}' in plasmid backbone(s) '{backbone_or_locus}'" ) plasmid = sbol3.Component(f'{display_id}_template', sbol3.SBO_DNA) document.add(plasmid) part_sub = sbol3.LocalSubComponent([sbol3.SBO_DNA], name="Inserted Construct") plasmid.features.append(part_sub) plasmid_cd = sbol3.CombinatorialDerivation(display_id, plasmid, name=name) document.add(plasmid_cd) part_var = sbol3.VariableFeature(cardinality=sbol3.SBOL_ONE, variable=part_sub) plasmid_cd.variable_features.append(part_var) part_var.variant_derivations.append(composite_part) if final_product: final_products.members.append(plasmid_cd) else: if len(backbones) == 1: logging.debug( f'Embedding part "{composite_part.name}" in plasmid backbone "{backbone_or_locus}"' ) plasmid = sbol3.Component(display_id, sbol3.SBO_DNA, name=name) document.add(plasmid) part_sub = sbol3.SubComponent(composite_part) plasmid.features.append(part_sub) if final_product: final_products.members += {plasmid} else: logging.debug( f'Embedding part "{composite_part.name}" in plasmid library "{backbone_or_locus}"' ) plasmid = sbol3.Component(f'{display_id}_template', sbol3.SBO_DNA) document.add(plasmid) part_sub = sbol3.SubComponent(composite_part) plasmid.features.append(part_sub) plasmid_cd = sbol3.CombinatorialDerivation(display_id, plasmid, name=name) document.add(plasmid_cd) if final_product: final_products.members.append(plasmid_cd) if len(backbones) == 1: backbone_sub = sbol3.SubComponent(backbones[0]) plasmid.features.append(backbone_sub) else: backbone_sub = sbol3.LocalSubComponent([sbol3.SBO_DNA]) backbone_sub.name = "Vector" plasmid.features.append(backbone_sub) backbone_var = sbol3.VariableFeature(cardinality=sbol3.SBOL_ONE, variable=backbone_sub) plasmid_cd.variable_features.append(backbone_var) backbone_var.variants += backbones plasmid.constraints.append( sbol3.Constraint(sbol3.SBOL_MEETS, part_sub, backbone_sub)) plasmid.constraints.append( sbol3.Constraint(sbol3.SBOL_MEETS, backbone_sub, part_sub))
def subcomponents(self): # if type is compdef do one thing, if combdev do another, else error if isinstance(self.obj, sbol3.component.Component): for sub in self.cell_val: sub_part = sbol3.SubComponent(f'{sbol3.get_namespace()}{sub}') self.obj.features.append(sub_part) # self.obj.assemblePrimaryStructure(self.cell_val) # self.obj.compile(assembly_method=None) elif isinstance(self.obj, sbol3.combderiv.CombinatorialDerivation): comp_list = self.cell_val comp_ind = 0 variant_comps = {} for ind, comp in enumerate(comp_list): if "," in comp: comp_list[ ind] = f'{self.obj.displayId}_subcomponent_{comp_ind}' uri = f'{self.obj.displayId}_subcomponent_{comp_ind}' sub_comp = sbol3.Component(uri, sbol3.SBO_DNA) sub_comp.displayId = f'{self.obj.displayId}_subcomponent_{comp_ind}' self.doc.add(sub_comp) variant_comps[f'subcomponent_{comp_ind}'] = { 'object': sub_comp, 'variant_list': comp } comp_ind += 1 # # move this to the object creation section # template = sbol2.ComponentDefinition(f'{self.obj.displayId}_template') # template.displayId = f'{self.obj.displayId}_template' # self.doc.add(template) template = self.obj_dict[f'{self.obj.displayId}_template'][ 'object'] for sub in comp_list: name = f'{sbol3.get_namespace()}{sub}' name = hf.check_name(name) sub_part = sbol3.SubComponent(name) template.features.append(sub_part) # template.assemblePrimaryStructure(comp_list) # template.compile(assembly_method=None) self.obj.masterTemplate = template for var in variant_comps: var_comp = sbol3.VariableFeature(cardinality=sbol3.SBOL_ONE, variable=f'var_{var}') var_comp.displayId = f'var_{var}' var_comp.variable = variant_comps[var]['object'] var_list = re.split(",", variant_comps[var]['variant_list']) var_list = [ f'{sbol3.get_namespace()}{x.strip()}' for x in var_list ] var_comp.variants = var_list self.obj.variable_features.append(var_comp) else: raise KeyError( f'The object type "{type(self.obj)}" does not allow subcomponents. (sheet:{self.sheet}, row:{self.sht_row}, col:{self.sht_col})' )
# RBS utr1 = sbol3.Component('UTR1', sbol3.SBO_DNA) utr1.roles = [sbol3.SO_RBS] utr1.description = 'Your Description Here' # Create the GFP coding sequence gfp = sbol3.Component('GFP', sbol3.SBO_DNA) gfp.roles.append(sbol3.SO_CDS) gfp.name = 'GFP' gfp.description = 'GFP Coding Sequence' # Wrap it together circuit = sbol3.Component('circuit', sbol3.SBO_DNA) circuit.roles.append(sbol3.SO_ENGINEERED_REGION) ptet_sc = sbol3.SubComponent(ptet) op1_sc = sbol3.SubComponent(op1) utr1_sc = sbol3.SubComponent(utr1) gfp_sc = sbol3.SubComponent(gfp) # circuit.features can be set and appended to like any Python list circuit.features = [ptet_sc, op1_sc] circuit.features += [utr1_sc] circuit.features.append(gfp_sc) circuit.constraints = [ sbol3.Constraint(sbol3.SBOL_PRECEDES, ptet_sc, op1_sc), sbol3.Constraint(sbol3.SBOL_PRECEDES, op1_sc, utr1_sc), sbol3.Constraint(sbol3.SBOL_PRECEDES, utr1_sc, gfp_sc) ]
def test_invalid_create(self): # SubComponent requires an `instance_of` argument sc = sbol3.SubComponent(None) report = sc.validate() self.assertIsNotNone(report) self.assertEqual(1, len(report.errors))
def derivation_to_collection( self, cd: sbol3.CombinatorialDerivation) -> sbol3.Collection: """Takes a CombinatorialDerivation and list of all those previously expanded, return a Collection of all of the variants generated from the CD, which have been added to its containing document Method: recursively instantiate all variables of the document We'll do this by a simple depth first search initially, since the numbers shouldn't be too large :param cd: derivation to expand :return: collection of derivative Components """ doc = cd.document sbol3.set_namespace( cd.namespace ) # use the namespace of the CD for all of its products sort_owned_objects(cd.template.lookup( )) # TODO: https://github.com/SynBioDex/pySBOL3/issues/231 # we've already converted this CombinatorialDerivation to a Collection, just return the conversion if cd in self.expanded_derivations.keys(): logging.debug('Found previous expansion of ' + cd.display_id) return self.expanded_derivations[cd] # if it doesn't already exist, we'll build it logging.debug("Expanding combinatorial derivation " + cd.display_id) # first get all of the values values = [ id_sort(self.cd_variable_values(v)) for v in id_sort(cd.variable_features) ] # if this is de facto a collection rather than a CD, just return it directly if is_library(cd): logging.debug("Interpreting combinatorial derivation " + cd.display_id + " as library") derivatives = sbol3.Collection(cd.identity + "_collection") doc.add(derivatives) derivatives.members += values[0] else: derivatives = sbol3.Collection(cd.identity + "_derivatives") doc.add(derivatives) # create a product-space of all of the possible assignments, then evaluate each in a scratch document assignments = itertools.product(*values) for a in assignments: # scratch_doc = sbol3.Document() derived = cd.template.lookup().clone( cd_assigment_to_display_id(cd, a)) logging.debug("Considering derived combination " + derived.display_id) # scratch_doc.add(derived) # add to the scratch document to enable manipulation of children doc.add( derived ) # add to the scratch document to enable manipulation of children # Replace variables with values newsubs = { derived.features[cd.template.lookup().features.index( f.variable.lookup())]: sbol3.SubComponent(v) for f, v in zip(id_sort(cd.variable_features), a) } for f in id_sort(newsubs.keys()): replace_feature(derived, f, newsubs[f]) # Need to remap everything that points to this feature as well # TODO: confirm that variant satisfies constraints # If constraints are satisfied, then copy back and add to success list # derived.copy(input_doc) derivatives.members.append(derived) # remember and return the collection of all successful derivatives self.expanded_derivations[cd] = derivatives return derivatives