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
29 changes: 28 additions & 1 deletion sbol_utilities/helper_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,4 +363,31 @@ def is_circular(obj: Union[sbol3.Component, sbol3.LocalSubComponent, sbol3.Exter
:param obj: design to be checked
:return: true if circular
"""
return any(n==sbol3.SO_CIRCULAR for n in obj.types)
return any(n==sbol3.SO_CIRCULAR for n in obj.types)

def is_composite(obj):
"""Check if an SBOL Component is a composite.

A composite component is defined as:
1. Having a DNA type.
2. Being generated by an assembly plan activity.

:param obj: SBOL Component to be checked.
:return: True if the component is composite, otherwise False.
"""

def has_dna_type(o):
"""Check if the component has a DNA type."""
return any(tyto.SO.DNA == tyto.SO.get_uri_by_term(t) for t in o.types)

def has_assembly_plan(o):
"""Check if the component was generated by an assembly plan."""
for activity_ref in o.generated_by:
activity = activity_ref.lookup()
if activity and 'http://sbols.org/v3#assemblyPlan' in activity.types and sbol3.SBOL_DESIGN in activity.types:
return True
return False

if isinstance(obj, sbol3.Component):
return has_dna_type(obj) and has_assembly_plan(obj)
return False
32 changes: 32 additions & 0 deletions test/test_helpers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import unittest
import os
from pathlib import Path
import sbol3
import tyto

from sbol_utilities import component

Expand Down Expand Up @@ -31,6 +33,36 @@ def test_url_sanitization(self):
self.assertEqual(strip_filetype_suffix('http://foo/bar/baz.gb'), 'http://foo/bar/baz')
self.assertEqual(strip_filetype_suffix('http://foo/bar/baz.qux'), 'http://foo/bar/baz.qux')

def test_is_composite(self):
"""Test the is_composite function."""
# Set up a test SBOL document and namespace
doc = sbol3.Document()
sbol3.set_namespace('http://sbolstandard.org/test')
# Case 1: Valid composite component (Has DNA type + Assembly Plan)
comp1 = sbol3.Component('comp1', types=[tyto.SO.DNA])
assembly_activity = sbol3.Activity('activity1')
assembly_activity.types.append("http://sbols.org/v3#assemblyPlan")
assembly_activity.types.append(sbol3.SBOL_DESIGN)
# Add activity to the document
doc.add(assembly_activity)
comp1.generated_by.append(sbol3.ReferencedObject(assembly_activity.identity))
doc.add(comp1)
self.assertTrue(is_composite(comp1), "Expected comp1 to be composite")
# Case 2: Not composite (No DNA type, but has Assembly Plan)
comp2 = sbol3.Component('comp2', types=[tyto.SO.RNA]) # RNA type instead of DNA
comp2.generated_by.append(sbol3.ReferencedObject(assembly_activity.identity))
doc.add(comp2)
self.assertFalse(is_composite(comp2), "Expected comp2 to NOT be composite")
# Case 3: Not composite (Has DNA type, but no Assembly Plan)
comp3 = sbol3.Component('comp3', types=[tyto.SO.DNA])
doc.add(comp3)
self.assertFalse(is_composite(comp3), "Expected comp3 to NOT be composite")
# Case 4: Not composite (No DNA type, No Assembly Plan)
comp4 = sbol3.Component('comp4', types=[tyto.SO.RNA])
doc.add(comp4)
self.assertFalse(is_composite(comp4), "Expected comp4 to NOT be composite")


def test_filtering_top_level_objects(self):
"""Check filtering Top Level Objects by a condition"""
test_dir = os.path.dirname(os.path.realpath(__file__))
Expand Down