From 0f5e1dec3c4312898b96757ef06b1abd7dae610e Mon Sep 17 00:00:00 2001 From: GeneCodeSavvy Date: Fri, 2 May 2025 15:49:30 +0530 Subject: [PATCH 1/6] fix misspelled variable name --- sbol_utilities/sbol3_sbol2_conversion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbol_utilities/sbol3_sbol2_conversion.py b/sbol_utilities/sbol3_sbol2_conversion.py index 19485ecb..be3342dc 100644 --- a/sbol_utilities/sbol3_sbol2_conversion.py +++ b/sbol_utilities/sbol3_sbol2_conversion.py @@ -752,7 +752,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) From 49a536ea55cec3af47d3903c680f32f4218e645a Mon Sep 17 00:00:00 2001 From: GeneCodeSavvy Date: Thu, 24 Jul 2025 17:29:49 +0530 Subject: [PATCH 2/6] convert attachment objects sbol3 to sbol2 --- sbol_utilities/sbol3_sbol2_conversion.py | 36 ++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/sbol_utilities/sbol3_sbol2_conversion.py b/sbol_utilities/sbol3_sbol2_conversion.py index be3342dc..76d35641 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,38 @@ 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') + # Make the Attachment object and add it to the document + att2 = sbol2.Attachment(self._sbol2_identity(a), source=a.source, version=self._sbol2_version(a)) + self.doc2.addAttachment(att2) + + # Handle hash and hash_algorithm properties + if a.hash: + # Check if hash_algorithm is specified + hash_algorithm = a.hash_algorithm + + # Check if it's SHA1 (SBOL2 only supports SHA1) + # Common SHA1 identifiers + sha1_identifiers = [ + 'SHA1', + 'sha1', + 'SHA-1', + 'sha-1' + ] + + if any(sha1_id in str(hash_algorithm) for sha1_id in sha1_identifiers): + # 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 = a.format + att2.size = a.size + + # Map over all other TopLevel properties and extensions not covered by the constructor + self._convert_toplevel(a, att2) + def visit_binary_prefix(self, a: sbol3.BinaryPrefix): # Priority: 4 From 3fb268044059c3408e30d5c17c2089f72cafc24b Mon Sep 17 00:00:00 2001 From: GeneCodeSavvy Date: Thu, 24 Jul 2025 17:31:44 +0530 Subject: [PATCH 3/6] convert attachment objects sbol2 to sbol3 --- sbol_utilities/sbol3_sbol2_conversion.py | 35 ++++++++++++------------ 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/sbol_utilities/sbol3_sbol2_conversion.py b/sbol_utilities/sbol3_sbol2_conversion.py index 76d35641..a125fa32 100644 --- a/sbol_utilities/sbol3_sbol2_conversion.py +++ b/sbol_utilities/sbol3_sbol2_conversion.py @@ -150,25 +150,14 @@ 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): - # Make the Attachment object and add it to the document att2 = sbol2.Attachment(self._sbol2_identity(a), source=a.source, version=self._sbol2_version(a)) self.doc2.addAttachment(att2) - # Handle hash and hash_algorithm properties if a.hash: - # Check if hash_algorithm is specified - hash_algorithm = a.hash_algorithm - # Check if it's SHA1 (SBOL2 only supports SHA1) - # Common SHA1 identifiers - sha1_identifiers = [ - 'SHA1', - 'sha1', - 'SHA-1', - 'sha-1' - ] + hash_algorithm = a.hash_algorithm - if any(sha1_id in str(hash_algorithm) for sha1_id in sha1_identifiers): + if hash_algorithm.replace("-", "").replace(" ", "").lower() == 'sha1': # It's SHA1, so we can set it directly in SBOL2 att2.hash = a.hash else: @@ -176,10 +165,9 @@ def visit_attachment(self, a: sbol3.Attachment): att2.properties[BACKPORT_NAMESPACE + 'hash'] = [Literal(a.hash)] att2.properties[BACKPORT_NAMESPACE + 'hashAlgorithm'] = [Literal(hash_algorithm)] - att2.format = a.format + att2.format = str(a.format) att2.size = a.size - # Map over all other TopLevel properties and extensions not covered by the constructor self._convert_toplevel(a, att2) @@ -571,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 From 317acbd4f9af400852165379918949a3560d9018 Mon Sep 17 00:00:00 2001 From: GeneCodeSavvy Date: Wed, 6 Aug 2025 02:19:28 +0530 Subject: [PATCH 4/6] add test files for attachment conversion tests --- .../test_attachment_sbol2_converted.xml | 18 ++++++++++++++ .../test_attachment_sbol2_converted_loop.xml | 8 +++---- test/test_files/test_attachment_sbol3.xml | 6 ++--- .../test_attachment_sbol3_converted.xml | 12 ++++++++++ .../test_attachment_sbol3_converted_loop.xml | 24 +++++++++++++++++++ 5 files changed, 61 insertions(+), 7 deletions(-) create mode 100644 test/test_files/test_attachment_sbol2_converted.xml create mode 100644 test/test_files/test_attachment_sbol3_converted.xml create mode 100644 test/test_files/test_attachment_sbol3_converted_loop.xml diff --git a/test/test_files/test_attachment_sbol2_converted.xml b/test/test_files/test_attachment_sbol2_converted.xml new file mode 100644 index 00000000..7e158c1a --- /dev/null +++ b/test/test_files/test_attachment_sbol2_converted.xml @@ -0,0 +1,18 @@ + + + + exp1_growth_data + + + + + 147 + 8d297ddafd1955b6095356582c13a58f23a1a133 + sha1 + 1 + + diff --git a/test/test_files/test_attachment_sbol2_converted_loop.xml b/test/test_files/test_attachment_sbol2_converted_loop.xml index 0ecbc98c..37f5cfcf 100644 --- a/test/test_files/test_attachment_sbol2_converted_loop.xml +++ b/test/test_files/test_attachment_sbol2_converted_loop.xml @@ -1,12 +1,12 @@ - - exp1_growth_data - 1 - 8d297ddafd1955b6095356582c13a58f23a1a133 147 + 1 + + exp1_growth_data + 8d297ddafd1955b6095356582c13a58f23a1a133 diff --git a/test/test_files/test_attachment_sbol3.xml b/test/test_files/test_attachment_sbol3.xml index 2356f804..d4fb9736 100644 --- a/test/test_files/test_attachment_sbol3.xml +++ b/test/test_files/test_attachment_sbol3.xml @@ -3,10 +3,10 @@ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sbol="http://sbols.org/v3#" > - - exp1_growth_data + + attachment1 - + 147 diff --git a/test/test_files/test_attachment_sbol3_converted.xml b/test/test_files/test_attachment_sbol3_converted.xml new file mode 100644 index 00000000..73d087d8 --- /dev/null +++ b/test/test_files/test_attachment_sbol3_converted.xml @@ -0,0 +1,12 @@ + + + + 147 + + sha256 + + + c531131f1bfc4c56b1d49a8caf389ac744263582163df2a6aab45916f2eab045 + attachment1 + + diff --git a/test/test_files/test_attachment_sbol3_converted_loop.xml b/test/test_files/test_attachment_sbol3_converted_loop.xml new file mode 100644 index 00000000..75b5408c --- /dev/null +++ b/test/test_files/test_attachment_sbol3_converted_loop.xml @@ -0,0 +1,24 @@ + + + + attachment1 + Dummy Attachment + A dummy attachment object + + + + + 1024 + + + promoter1 + Dummy Promoter + A dummy promoter component for demonstration purposes + + + + + From 8bed8ce586cf7653cf88ad8e2060dbce19239144 Mon Sep 17 00:00:00 2001 From: GeneCodeSavvy Date: Sun, 26 Oct 2025 00:54:26 +0530 Subject: [PATCH 5/6] feat: tests for attachment objects --- test/test_sbol2_sbol3_direct.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/test/test_sbol2_sbol3_direct.py b/test/test_sbol2_sbol3_direct.py index 74ba6acf..edc8aea8 100644 --- a/test/test_sbol2_sbol3_direct.py +++ b/test/test_sbol2_sbol3_direct.py @@ -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 @@ -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): @@ -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): @@ -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 @@ -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): @@ -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() From e4dfba55864007fe0a1ad1850266c9dd51299aed Mon Sep 17 00:00:00 2001 From: GeneCodeSavvy Date: Sun, 26 Oct 2025 01:22:10 +0530 Subject: [PATCH 6/6] bug: update hash test --- test/test_helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_helpers.py b/test/test_helpers.py index 5960e747..f7b7b0a4 100644 --- a/test/test_helpers.py +++ b/test/test_helpers.py @@ -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)