Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 46 additions & 19 deletions sbol_utilities/sbol3_sbol2_conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,9 +389,22 @@ def visit_sequence(self, seq3: sbol3.Sequence):
# Map over all other TopLevel properties and extensions not covered by the constructor
self._convert_toplevel(seq3, seq2)

def visit_sequence_feature(self, a: sbol3.SequenceFeature):
# Priority: 1
raise NotImplementedError('Conversion of SequenceFeature from SBOL3 to SBOL2 not yet implemented')
def visit_sequence_feature(self, seqfeat3: sbol3.SequenceFeature):
# Priority: 1
# SBOL 2.x SequenceAnnotation objects map to SBOL 3.x SequenceFeature objects if they do not have a component.
# If they do have a component, their locations are added to the corresponding SBOL3 SubComponent.

# convert locations
locations2 = [loc3.accept(self) for loc3 in seqfeat3.locations]

# Create SBOL2 SequenceAnnotation
seqanno2 = sbol2.SequenceAnnotation(uri=self._sbol3_identity(seqfeat3),
locations=locations2,
roles=seqfeat3.roles,
version=self._sbol2_version(seqfeat3)
)
self._convert_identified(seqfeat3, seqanno2)
return seqanno2, locations2

def visit_singular_unit(self, a: sbol3.SingularUnit):
# Priority: 4
Expand Down Expand Up @@ -752,7 +765,7 @@ def visit_range(self, r2: sbol2.Range):
cdef = r2.parent.parent
ns = self._sbol3_namespace(cdef)
seq_stub = sbol3.Sequence(f'{ns}/{cdef.displayId}Seq/', namespace=ns)
cdef.sequence = seq_stup
cdef.sequence = seq_stub
cdef.doc.add(seq_stub)
r3 = sbol3.Range(seq_ref, r2.start, r2.end)
self._convert_identified(r2, r3)
Expand All @@ -772,21 +785,35 @@ def visit_sequence(self, seq2: sbol2.Sequence):
# Map over all other TopLevel properties and extensions not covered by the constructor
self._convert_toplevel(seq2, seq3)

def visit_sequence_annotation(self, sa2: sbol2.SequenceAnnotation):
# component URIRef 0..1
# orientation URI 0..1
locations = []
for l2 in sa2.locations:
if type(l2) == sbol2.Range:
l3 = self.visit_range(l2)
else:
raise NotImplementedError('Conversion of {type(l2)} from SBOL2 to SBOL3 not yet implemented')
locations.append(l3)

f3 = sbol3.SequenceFeature(locations)
f3.roles = sa2.roles
self._convert_identified(sa2, f3)
return f3, locations
def visit_sequence_annotation(self, seqanno2: sbol2.SequenceAnnotation):
# Priority: 1
# SBOL 2.x SequenceAnnotation objects map to SBOL 3.x SequenceFeature objects if they do not have a component.
# If they do have a component, their locations are added to the corresponding SBOL3 SubComponent.
def _handle_locations(loc2):
if type(loc2) is sbol2.location.Range:
return self.visit_range(loc2)
elif type(loc2) is sbol2.location.Cut:
raise NotImplementedError('Conversion of Cut from SBOL2 to SBOL3 not yet implemented')
elif type(loc2) is sbol2.location.GenericLocation:
raise NotImplementedError('Conversion of GenericLocation from SBOL2 to SBOL3 not yet implemented')
else: raise ValueError(f'Unknown location type {type(loc2)}, SequenceAnnotation cannot convert to SBOL3')
# convert locations
locations3 = [_handle_locations(loc2) for loc2 in seqanno2.locations]

# Create SBOL3 SequenceFeature
if seqanno2.component:
feature3 = sbol3.SubComponent(instance_of=seqanno2.component, #TODO: verify if this is correct
locations=locations3,
roles=seqanno2.roles,
)
else:
feature3 = sbol3.SequenceFeature(identity=self._sbol3_identity(seqanno2),
locations=locations3,
roles=seqanno2.roles,
)
self._convert_identified(seqanno2, feature3)
return feature3, locations3


def visit_sequence_constraint(self, seq2: sbol2.sequenceconstraint.SequenceConstraint):
# Priority: 2
Expand Down
33 changes: 33 additions & 0 deletions test/test_files/sbol_3to2_sequence_annotation.nt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<rdf:RDF xmlns:brick="https://brickschema.org/schema/Brick#" xmlns:csvw="http://www.w3.org/ns/csvw#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcat="http://www.w3.org/ns/dcat#" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcam="http://purl.org/dc/dcam/" xmlns:doap="http://usefulinc.com/ns/doap#" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:geo="http://www.opengis.net/ont/geosparql#" xmlns:odrl="http://www.w3.org/ns/odrl/2/" xmlns:org="http://www.w3.org/ns/org#" xmlns:prof="http://www.w3.org/ns/dx/prof/" xmlns:prov="http://www.w3.org/ns/prov#" xmlns:qb="http://purl.org/linked-data/cube#" xmlns:schema="https://schema.org/" xmlns:sh="http://www.w3.org/ns/shacl#" xmlns:skos="http://www.w3.org/2004/02/skos/core#" xmlns:sosa="http://www.w3.org/ns/sosa/" xmlns:ssn="http://www.w3.org/ns/ssn/" xmlns:time="http://www.w3.org/2006/time#" xmlns:vann="http://purl.org/vocab/vann/" xmlns:void="http://rdfs.org/ns/void#" xmlns:wgs="https://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:owl="http://www.w3.org/2002/07/owl#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:xsd="http://www.w3.org/2001/XMLSchema#" xmlns:backport="http://sboltools.org/backport#" xmlns:sbol="http://sbols.org/v2#">
<sbol:Sequence rdf:about="https://github.com/sequence1">
<sbol:persistentIdentity rdf:resource="https://github.com/sequence1"/>
<sbol:elements>gattaca</sbol:elements>
<sbol:displayId>sequence1</sbol:displayId>
<backport:sbol3namespace rdf:resource="https://github.com/"/>
<sbol:encoding rdf:resource="http://www.chem.qmul.ac.uk/iubmb/misc/naseq.html"/>
</sbol:Sequence>
<sbol:ComponentDefinition rdf:about="https://github.com/component1">
<sbol:displayId>component1</sbol:displayId>
<sbol:sequenceAnnotation>
<sbol:SequenceAnnotation rdf:about="https://github.com/component1/SequenceFeature1">
<sbol:location>
<sbol:Range rdf:about="https://github.com/component1/SequenceFeature1/Range1">
<sbol:displayId>Range1</sbol:displayId>
<sbol:persistentIdentity rdf:resource="https://github.com/component1/SequenceFeature1/Range1"/>
<sbol:end>3</sbol:end>
<sbol:start>1</sbol:start>
</sbol:Range>
</sbol:location>
<sbol:displayId>SequenceFeature1</sbol:displayId>
<dcterms:title>promoter_feature</dcterms:title>
<sbol:role rdf:resource="https://identifiers.org/SO:0000167"/>
<sbol:persistentIdentity rdf:resource="https://github.com/component1/SequenceFeature1"/>
</sbol:SequenceAnnotation>
</sbol:sequenceAnnotation>
<sbol:type rdf:resource="http://www.biopax.org/release/biopax-level3.owl#DnaRegion"/>
<backport:sbol3identity rdf:resource="https://github.com/component1"/>
<sbol:persistentIdentity rdf:resource="https://github.com/component1"/>
<backport:sbol3namespace rdf:resource="https://github.com/"/>
<sbol:sequence rdf:resource="https://github.com/sequence1"/>
</sbol:ComponentDefinition>
</rdf:RDF>
35 changes: 35 additions & 0 deletions test/test_files/sbol_3to2_sequence_feature.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:sbol="http://sbols.org/v3#"
>
<rdf:Description rdf:about="https://github.com/component1">
<sbol:displayId>component1</sbol:displayId>
<rdf:type rdf:resource="http://sbols.org/v3#Component"/>
<sbol:hasNamespace rdf:resource="https://github.com/"/>
<sbol:type rdf:resource="https://identifiers.org/SBO:0000251"/>
<sbol:hasSequence rdf:resource="https://github.com/sequence1"/>
<sbol:hasFeature rdf:resource="https://github.com/component1/SequenceFeature1"/>
</rdf:Description>
<rdf:Description rdf:about="https://github.com/sequence1">
<sbol:displayId>sequence1</sbol:displayId>
<rdf:type rdf:resource="http://sbols.org/v3#Sequence"/>
<sbol:hasNamespace rdf:resource="https://github.com/"/>
<sbol:elements>gattaca</sbol:elements>
<sbol:encoding rdf:resource="https://identifiers.org/edam:format_1207"/>
</rdf:Description>
<rdf:Description rdf:about="https://github.com/component1/SequenceFeature1/Range1">
<sbol:displayId>Range1</sbol:displayId>
<rdf:type rdf:resource="http://sbols.org/v3#Range"/>
<sbol:hasSequence rdf:resource="https://github.com/sequence1"/>
<sbol:start rdf:datatype="http://www.w3.org/2001/XMLSchema#integer">1</sbol:start>
<sbol:end rdf:datatype="http://www.w3.org/2001/XMLSchema#integer">3</sbol:end>
</rdf:Description>
<rdf:Description rdf:about="https://github.com/component1/SequenceFeature1">
<sbol:displayId>SequenceFeature1</sbol:displayId>
<sbol:name>promoter_feature</sbol:name>
<rdf:type rdf:resource="http://sbols.org/v3#SequenceFeature"/>
<sbol:role rdf:resource="https://identifiers.org/SO:0000167"/>
<sbol:hasLocation rdf:resource="https://github.com/component1/SequenceFeature1/Range1"/>
</rdf:Description>
</rdf:RDF>
7 changes: 6 additions & 1 deletion test/test_sbol2_sbol3_direct.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,9 @@ def test_functionalcomponent_conversion(self):
def test_interaction_conversion(self):
self.handle_2to3_conversion('sbol_3to2_interaction.xml', 'sbol_3to2_interaction.nt')

def test_seq_annotation_conversion(self):
self.handle_2to3_conversion('sbol_3to2_sequence_annotation.nt', 'sbol_3to2_sequence_feature.nt')


class TestDirectSBOL3SBOL2Conversion(unittest.TestCase):

Expand Down Expand Up @@ -373,6 +376,8 @@ def test_identity_conversion(self):
def test_interaction_conversion(self):
self.handle_3to2_conversion('sbol_3to2_interaction.nt', 'sbol_3to2_interaction.xml')


def test_seq_feature_conversion(self):
self.handle_3to2_conversion('sbol_3to2_sequence_feature.xml', 'sbol_3to2_sequence_annotation.nt')

if __name__ == '__main__':
unittest.main()
Loading