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
43 changes: 37 additions & 6 deletions sbol_utilities/sbol3_sbol2_conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@


# Namespaces
from rdflib import URIRef
from rdflib import URIRef, Literal

BACKPORT_NAMESPACE = 'http://sboltools.org/backport#'
BACKPORT2_VERSION = f'{BACKPORT_NAMESPACE}sbol2version'
Expand Down Expand Up @@ -150,8 +150,26 @@ def visit_association(self, a: sbol3.Association):
raise NotImplementedError('Conversion of Association from SBOL3 to SBOL2 not yet implemented')

def visit_attachment(self, a: sbol3.Attachment):
# Priority: 2
raise NotImplementedError('Conversion of Attachment from SBOL3 to SBOL2 not yet implemented')
att2 = sbol2.Attachment(self._sbol2_identity(a), source=a.source, version=self._sbol2_version(a))
self.doc2.addAttachment(att2)

if a.hash:
# Check if it's SHA1 (SBOL2 only supports SHA1)
hash_algorithm = a.hash_algorithm

if hash_algorithm.replace("-", "").replace(" ", "").lower() == 'sha1':
# It's SHA1, so we can set it directly in SBOL2
att2.hash = a.hash
else:
# It's not SHA1, add as backport extension properties
att2.properties[BACKPORT_NAMESPACE + 'hash'] = [Literal(a.hash)]
att2.properties[BACKPORT_NAMESPACE + 'hashAlgorithm'] = [Literal(hash_algorithm)]

att2.format = str(a.format)
att2.size = a.size

self._convert_toplevel(a, att2)


def visit_binary_prefix(self, a: sbol3.BinaryPrefix):
# Priority: 4
Expand Down Expand Up @@ -541,8 +559,21 @@ def visit_association(self, a: sbol2.Association):
raise NotImplementedError('Conversion of Association from SBOL2 to SBOL3 not yet implemented')

def visit_attachment(self, a: sbol2.Attachment):
# Priority: 2
raise NotImplementedError('Conversion of Attachment from SBOL2 to SBOL3 not yet implemented')
att3 = sbol3.Attachment(self._sbol3_identity(a), namespace=self._sbol3_namespace(a), source=a.source)
self.doc3.add(att3)

# Check for backported hash properties first (higher priority)
if BACKPORT_NAMESPACE + 'hash' in a.properties:
att3.hash = a.properties[BACKPORT_NAMESPACE + 'hash'][0]
att3.hash_algorithm = a.properties[BACKPORT_NAMESPACE + 'hashAlgorithm'][0]
elif a.hash:
att3.hash = a.hash
att3.hash_algorithm = 'sha1'

att3.format = str(a.format)
att3.size = a.size

self._convert_toplevel(a, att3)

def visit_collection(self, coll2: sbol2.Collection):
# Make the Collection object and add it to the document
Expand Down Expand Up @@ -752,7 +783,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 Down
18 changes: 18 additions & 0 deletions test/test_files/test_attachment_sbol2_converted.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<rdf:RDF
xmlns:ns1="http://sboltools.org/backport#"
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/1/SynBioDex/SBOL-Notebooks/Attachment/exp1_growth_data">
<sbol:displayId>exp1_growth_data</sbol:displayId>
<rdf:type rdf:resource="http://sbols.org/v3#Attachment"/>
<sbol:hasNamespace rdf:resource="https://github.com"/>
<sbol:source rdf:resource="https://raw.githubusercontent.com/SynBioDex/SBOL-Notebooks/1e4d133dfeb313695f2cee394a580d2569ce6892/examples/sbol2/CreatingSBOL2Objects/plate_reader_exp1.csv"/>
<sbol:format rdf:resource="http://edamontology.org/format_3752"/>
<sbol:size rdf:datatype="http://www.w3.org/2001/XMLSchema#integer">147</sbol:size>
<sbol:hash>8d297ddafd1955b6095356582c13a58f23a1a133</sbol:hash>
<sbol:hashAlgorithm>sha1</sbol:hashAlgorithm>
<ns1:sbol2version>1</ns1:sbol2version>
</rdf:Description>
</rdf:RDF>
8 changes: 4 additions & 4 deletions test/test_files/test_attachment_sbol2_converted_loop.xml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<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:om="http://www.ontology-of-units-of-measure.org/resource/om-2/" xmlns:sbol="http://sbols.org/v2#">
<sbol:Attachment rdf:about="https://github.com/SynBioDex/SBOL-Notebooks/Attachment/exp1_growth_data/1">
<backport:sbol3namespace rdf:resource="https://github.com"/>
<sbol:persistentIdentity rdf:resource="https://github.com/SynBioDex/SBOL-Notebooks/Attachment/exp1_growth_data"/>
<sbol:displayId>exp1_growth_data</sbol:displayId>
<sbol:version>1</sbol:version>
<sbol:hash>8d297ddafd1955b6095356582c13a58f23a1a133</sbol:hash>
<sbol:size>147</sbol:size>
<sbol:source rdf:resource="https://raw.githubusercontent.com/SynBioDex/SBOL-Notebooks/1e4d133dfeb313695f2cee394a580d2569ce6892/examples/sbol2/CreatingSBOL2Objects/plate_reader_exp1.csv"/>
<sbol:version>1</sbol:version>
<sbol:persistentIdentity rdf:resource="https://github.com/SynBioDex/SBOL-Notebooks/Attachment/exp1_growth_data"/>
<sbol:format rdf:resource="http://edamontology.org/format_3752"/>
<sbol:displayId>exp1_growth_data</sbol:displayId>
<sbol:hash>8d297ddafd1955b6095356582c13a58f23a1a133</sbol:hash>
</sbol:Attachment>
</rdf:RDF>
6 changes: 3 additions & 3 deletions test/test_files/test_attachment_sbol3.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
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/SynBioDex/SBOL-Notebooks/exp1_growth_data">
<sbol:displayId>exp1_growth_data</sbol:displayId>
<rdf:Description rdf:about="http://example.org/attachment1">
<sbol:displayId>attachment1</sbol:displayId>
<rdf:type rdf:resource="http://sbols.org/v3#Attachment"/>
<sbol:hasNamespace rdf:resource="https://github.com/SynBioDex/SBOL-Notebooks"/>
<sbol:hasNamespace rdf:resource="http://example.org"/>
<sbol:source rdf:resource="https://raw.githubusercontent.com/SynBioDex/SBOL-Notebooks/1e4d133dfeb313695f2cee394a580d2569ce6892/examples/sbol2/CreatingSBOL2Objects/plate_reader_exp1.csv"/>
<sbol:format rdf:resource="http://edamontology.org/format_3752"/>
<sbol:size rdf:datatype="http://www.w3.org/2001/XMLSchema#integer">147</sbol:size>
Expand Down
12 changes: 12 additions & 0 deletions test/test_files/test_attachment_sbol3_converted.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<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:om="http://www.ontology-of-units-of-measure.org/resource/om-2/" xmlns:sbol="http://sbols.org/v2#">
<sbol:Attachment rdf:about="http://example.org/attachment1">
<sbol:format rdf:resource="http://edamontology.org/format_3752"/>
<sbol:size>147</sbol:size>
<sbol:source rdf:resource="https://raw.githubusercontent.com/SynBioDex/SBOL-Notebooks/1e4d133dfeb313695f2cee394a580d2569ce6892/examples/sbol2/CreatingSBOL2Objects/plate_reader_exp1.csv"/>
<backport:hashAlgorithm>sha256</backport:hashAlgorithm>
<sbol:persistentIdentity rdf:resource="http://example.org/attachment1"/>
<backport:sbol3namespace rdf:resource="http://example.org"/>
<backport:hash>c531131f1bfc4c56b1d49a8caf389ac744263582163df2a6aab45916f2eab045</backport:hash>
<sbol:displayId>attachment1</sbol:displayId>
</sbol:Attachment>
</rdf:RDF>
24 changes: 24 additions & 0 deletions test/test_files/test_attachment_sbol3_converted_loop.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?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="http://example.org/attachment1">
<sbol:displayId>attachment1</sbol:displayId>
<sbol:name>Dummy Attachment</sbol:name>
<sbol:description>A dummy attachment object</sbol:description>
<rdf:type rdf:resource="http://sbols.org/v3#Attachment"/>
<sbol:hasNamespace rdf:resource="http://example.org"/>
<sbol:source rdf:resource="http://example.org/source_file.txt"/>
<sbol:format rdf:resource="file:///Users/harshsharma/Desktop/100xdevs/gsoc/SBOL-utilities/test/test_files/text/plain"/>
<sbol:size rdf:datatype="http://www.w3.org/2001/XMLSchema#integer">1024</sbol:size>
</rdf:Description>
<rdf:Description rdf:about="http://example.org/promoter1">
<sbol:displayId>promoter1</sbol:displayId>
<sbol:name>Dummy Promoter</sbol:name>
<sbol:description>A dummy promoter component for demonstration purposes</sbol:description>
<rdf:type rdf:resource="http://sbols.org/v3#Component"/>
<sbol:hasNamespace rdf:resource="http://example.org"/>
<sbol:type rdf:resource="https://identifiers.org/SBO:0000598"/>
</rdf:Description>
</rdf:RDF>
2 changes: 1 addition & 1 deletion test/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def test_generate_hash(self):
test_file = os.path.join(test_dir, 'test_files', 'test_attachment_sbol3.xml')
doc = sbol3.Document()
doc.read(test_file)
attachment: sbol3.Attachment = doc.find('exp1_growth_data')
attachment: sbol3.Attachment = doc.find('attachment1')

# 1. Test with a valid file and default algorithm (sha3_256)
hash = generate_hash(attachment)
Expand Down
14 changes: 10 additions & 4 deletions test/test_sbol2_sbol3_direct.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ def handle_2to3_conversion(self, test_filename: str, comparison_filename: str):
with tempfile.TemporaryDirectory() as tmpdir:
tmp3 = Path(tmpdir) / 'doc3.nt'
doc3.write(tmp3)
if file_diff(str(tmp3), str(TEST_FILES / comparison_filename)):
if file_diff(str(tmp3), str(TEST_FILES / comparison_filename), strip_backport_properties=True):
raise SBOL2to3ConversionError()

# Round-trip back to SBOL2 and check contents
Expand All @@ -294,7 +294,7 @@ def handle_2to3_conversion(self, test_filename: str, comparison_filename: str):

tmp2 = Path(tmpdir) / 'doc2_loop.xml'
doc2_loop.write(tmp2)
if file_diff(str(tmp2), str(TEST_FILES / test_filename)):
if file_diff(str(tmp2), str(TEST_FILES / test_filename), strip_backport_properties=True):
raise SBOL3to2ConversionError()

def test_implementation_conversion(self):
Expand All @@ -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_attachment_conversion(self):
"""Test ability to convert SBOL2 attachment objects to SBOL3"""
self.handle_2to3_conversion('test_attachment_sbol2.xml', 'test_attachment_sbol2_converted.xml')

class TestDirectSBOL3SBOL2Conversion(unittest.TestCase):

Expand All @@ -330,7 +333,7 @@ def handle_3to2_conversion(self, test_filename: str, comparison_filename: str):
with tempfile.TemporaryDirectory() as tmpdir:
tmp2 = Path(tmpdir) / 'doc2.xml'
doc2.write(tmp2)
if file_diff(str(tmp2), str(TEST_FILES / comparison_filename)):
if file_diff(str(tmp2), str(TEST_FILES / comparison_filename), strip_backport_properties=True):
raise SBOL3to2ConversionError()

# Round-trip back to SBOL3 and check contents
Expand All @@ -341,7 +344,7 @@ def handle_3to2_conversion(self, test_filename: str, comparison_filename: str):

tmp3 = Path(tmpdir) / 'doc3_loop.nt'
doc3_loop.write(tmp3)
if file_diff(str(tmp3), str(TEST_FILES / test_filename)):
if file_diff(str(tmp3), str(TEST_FILES / test_filename), strip_backport_properties=True):
raise SBOL2to3ConversionError()

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

def test_attachment_conversion(self):
"""Test ability to convert SBOL3 attachment objects to SBOL2"""
self.handle_3to2_conversion('test_attachment_sbol3.xml', 'test_attachment_sbol3_converted.xml')

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