def test_system_building(self): doc = sbol3.Document() sbol3.set_namespace('http://sbolstandard.org/testfiles') system = sbol3.Component('system', sbol3.SBO_FUNCTIONAL_ENTITY) doc.add(system) # make a couple of stand-alone components gfp_cds = sbol3.Component('gfp_cds', sbol3.SBO_DNA, roles=[tyto.SO.CDS]) doc.add(gfp_cds) # make a functional unit expression = add_feature( system, sbol3.LocalSubComponent([sbol3.SBO_DNA], roles=[tyto.SO.engineered_region])) contains(expression, gfp_cds) rbs = contains( expression, sbol3.LocalSubComponent([sbol3.SBO_DNA], roles=[tyto.SO.ribosome_entry_site])) regulate(rbs, gfp_cds) terminator = contains( expression, sbol3.LocalSubComponent([sbol3.SBO_DNA], roles=[tyto.SO.terminator])) order(gfp_cds, terminator) constitutive(expression) # link it to a product gfp_mut3_ncbi = 'https://www.ncbi.nlm.nih.gov/protein/AAB18957.1' gfp = add_feature( system, sbol3.ExternallyDefined([sbol3.SBO_PROTEIN], gfp_mut3_ncbi)) prod = add_interaction(sbol3.SBO_GENETIC_PRODUCTION, participants={ gfp: sbol3.SBO_PRODUCT, gfp_cds: sbol3.SBO_TEMPLATE }) assert contained_components(system) == {system, gfp_cds} assert in_role(prod, sbol3.SBO_PRODUCT) == gfp assert all_in_role(prod, sbol3.SBO_TEMPLATE) == [ ensure_singleton_feature(system, gfp_cds) ] # confirm that the system constructed is exactly as expected tmp_out = tempfile.mkstemp(suffix='.nt')[1] doc.write(tmp_out, sbol3.SORTED_NTRIPLES) test_dir = os.path.dirname(os.path.realpath(__file__)) comparison_file = os.path.join(test_dir, 'test_files', 'component_construction.nt') assert filecmp.cmp( tmp_out, comparison_file), f'Converted file {tmp_out} is not identical'
def test_iadd(self): # This is a test for the += operator, which is implemented as __iadd__() # When += is invoked the default __iadd__() implementation calls insert() # and calls set(). That confuses our auto-numbering of child object # identities. sbol3.set_namespace('https://github.com/synbiodex/pysbol3') doc = sbol3.Document() c1 = sbol3.Component('c1', sbol3.SBO_DNA) doc.add(c1) lsc1 = sbol3.LocalSubComponent([sbol3.SBO_DNA]) c1.features += [lsc1] self.assertEqual('LocalSubComponent1', lsc1.display_id) self.assertEqual(posixpath.join(c1.identity, lsc1.display_id), lsc1.identity) # TODO: Add checks for document at each step below self.assertEqual(doc, lsc1.document) lsc2 = sbol3.LocalSubComponent([sbol3.SBO_DNA]) c1.features += [lsc2] # Make sure lsc1 did not get renamed self.assertEqual('LocalSubComponent1', lsc1.display_id) self.assertEqual(posixpath.join(c1.identity, lsc1.display_id), lsc1.identity) self.assertEqual(doc, lsc1.document) self.assertEqual('LocalSubComponent2', lsc2.display_id) self.assertEqual(posixpath.join(c1.identity, lsc2.display_id), lsc2.identity) self.assertEqual(doc, lsc2.document) lsc3 = sbol3.LocalSubComponent([sbol3.SBO_DNA]) lsc4 = sbol3.LocalSubComponent([sbol3.SBO_DNA]) c1.features += [lsc3, lsc4] # Make sure lsc1 did not get renamed self.assertEqual('LocalSubComponent1', lsc1.display_id) self.assertEqual(posixpath.join(c1.identity, lsc1.display_id), lsc1.identity) self.assertEqual(doc, lsc1.document) # Make sure lsc2 did not get renamed self.assertEqual('LocalSubComponent2', lsc2.display_id) self.assertEqual(posixpath.join(c1.identity, lsc2.display_id), lsc2.identity) self.assertEqual(doc, lsc2.document) self.assertEqual('LocalSubComponent3', lsc3.display_id) self.assertEqual(posixpath.join(c1.identity, lsc3.display_id), lsc3.identity) self.assertEqual(doc, lsc3.document) self.assertEqual('LocalSubComponent4', lsc4.display_id) self.assertEqual(posixpath.join(c1.identity, lsc4.display_id), lsc4.identity) self.assertEqual(doc, lsc4.document)
def constitutive(target: Union[sbol3.Feature, sbol3.Component], system: Optional[sbol3.Component] = None)\ -> sbol3.Feature: """Add a constitutive promoter regulating the target feature :param target: 5' region for promoter to regulate :param system: optional explicit statement of system :return: newly created constitutive promoter """ # transform implicit arguments into explicit system = ensure_singleton_system(system, target) target = ensure_singleton_feature(system, target) # create a constitutive promoter and use it to regulate the target promoter = add_feature( system, sbol3.LocalSubComponent([sbol3.SBO_DNA], roles=[tyto.SO.constitutive_promoter])) regulate(promoter, target) # also add the promoter into any containers that hold the target # TODO: add lookups for constraints like we have for interactions containers = [ c.subject for c in system.constraints if c.restriction == sbol3.SBOL_CONTAINS and c.object == target.identity ] for c in containers: contains(c.lookup(), promoter) return promoter
def test_features(self): # See https://github.com/SynBioDex/pySBOL3/issues/149 # Note: this example was modified when fixing # https://github.com/SynBioDex/pySBOL3/issues/178 # media_variable is unused in the original example so # it has been commented out here media_template = sbol3.LocalSubComponent( types=[sbol3.SBO_FUNCTIONAL_ENTITY]) media_template.name = 'media template' # variable_uri = 'https://github.com/synbiodex/pysbol3/variable' # media_variable = sbol3.VariableFeature(cardinality=sbol3.SBOL_ONE, # variable=media_template) # media_variable.variable = media_template all_sample_templates = [media_template] sample_template_uri = 'https://sd2e.org/measurement_template' sample_template = sbol3.Component(identity=sample_template_uri, types=sbol3.SBO_FUNCTIONAL_ENTITY) sample_template.name = 'measurement template' sample_template.features = all_sample_templates self.assertEqual(1, len(sample_template.features)) self.assertEqual(media_template.identity, sample_template.features[0].identity)
def test_clone_bad_rename(self): # Tests that the dependent objects have consistent renaming namespace = 'https://github.com/synbiodex/pysbol3' sbol3.set_namespace(namespace) name = 'c1' c1 = sbol3.Component(name, types=[sbol3.SBO_DNA]) lsc1 = sbol3.LocalSubComponent(types=[sbol3.SBO_DNA]) lsc2 = sbol3.LocalSubComponent(types=[sbol3.SBO_DNA]) c1.features = [lsc1, lsc2] self.assertEqual('LocalSubComponent1', lsc1.display_id) self.assertEqual('LocalSubComponent2', lsc2.display_id) c1.features.remove(lsc1) self.assertListEqual([lsc2], list(c1.features)) self.assertEqual('LocalSubComponent2', lsc2.display_id) self.assertIsNotNone(c1.find('LocalSubComponent2')) clone_name = 'c1_prime' c1_prime = c1.clone(posixpath.join(namespace, clone_name)) self.assertIsNotNone(c1_prime.find('LocalSubComponent2'))
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') test_type = sbol3.SBO_DNA seq = sbol3.Sequence('seq1') test_loc = sbol3.EntireSequence(seq) lsc = sbol3.LocalSubComponent(types=test_type, locations=test_loc) self.assertEqual([test_type], lsc.types) self.assertEqual([test_loc], lsc.locations)
def test_remove_from_document_identified(self): # Test removing a non-TopLevel from the document. This should # not give an error sbol3.set_namespace('https://github.com/synbiodex/pysbol3') doc = sbol3.Document() # This should quietly succeed because the string is not in the # document doc.remove_object('foo') lsc = sbol3.LocalSubComponent(types=[sbol3.SBO_DNA]) # This should also quietly succeed because the local subcomponent # is also not in the document doc.remove_object(lsc)
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 test_set_document(self): # Ensure that document is set on child objects # See https://github.com/SynBioDex/pySBOL3/issues/176 sbol3.set_namespace('https://bioprotocols.org/paml/primitives/') doc = sbol3.Document() c = sbol3.Component("scratch", sbol3.SBO_DNA) doc.add(c) lsc = sbol3.LocalSubComponent([sbol3.SBO_DNA]) self.assertIsNone(lsc.document) c.features.append(lsc) self.assertIsNotNone(lsc.document) interaction = sbol3.Interaction([sbol3.SBO_DEGRADATION]) c.interactions.append(interaction) self.assertEqual(doc, interaction.document) p = sbol3.Participation([sbol3.SBO_REACTANT], lsc) interaction.participations.append(p) self.assertEqual(doc, p.document) resolved_lsc = p.participant.lookup() self.assertEqual(lsc, resolved_lsc) self.assertEqual(lsc.identity, resolved_lsc.identity)
def test_compose_then_set_document(self): # Ensure that document is set on child objects # See https://github.com/SynBioDex/pySBOL3/issues/230 sbol3.set_namespace('https://bioprotocols.org/paml/primitives/') c = sbol3.Component("scratch", sbol3.SBO_DNA) lsc = sbol3.LocalSubComponent([sbol3.SBO_DNA]) self.assertIsNone(lsc.document) c.features.append(lsc) doc = sbol3.Document() doc.add(c) self.assertIsNotNone(lsc.document) self.assertEqual(doc, lsc.document) interaction = sbol3.Interaction([sbol3.SBO_DEGRADATION]) p = sbol3.Participation([sbol3.SBO_REACTANT], lsc) interaction.participations.append(p) c.interactions.append(interaction) # Now that we've composed the objects, add them to the parent. # This should assign the document to all the objects in the hierarchy # See https://github.com/SynBioDex/pySBOL3/issues/230 self.assertEqual(doc, interaction.document) self.assertEqual(doc, p.document) resolved_lsc = p.participant.lookup() self.assertEqual(lsc, resolved_lsc) self.assertEqual(lsc.identity, resolved_lsc.identity)
def test_validation(self): types = [] lsc = sbol3.LocalSubComponent(types) report = lsc.validate() self.assertIsNotNone(report) self.assertEqual(1, len(report.errors))
def test_create(self): types = [sbol3.SBO_DNA] lsc = sbol3.LocalSubComponent(types) self.assertIsNotNone(lsc) self.assertEqual(types, lsc.types) self.assertEqual([], lsc.locations)
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))