diff --git a/sbol_utilities/sbol3_sbol2_conversion.py b/sbol_utilities/sbol3_sbol2_conversion.py index d93b1094..d21172ff 100644 --- a/sbol_utilities/sbol3_sbol2_conversion.py +++ b/sbol_utilities/sbol3_sbol2_conversion.py @@ -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' @@ -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 @@ -456,8 +474,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 @@ -632,7 +663,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)