Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

handle None namespace and version suffix in conversion #285

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
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
6 changes: 3 additions & 3 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ jobs:
matrix:
# Default builds are on Ubuntu
os: [ubuntu-latest]
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11']
python-version: ['3.9', '3.10', '3.11','3.12']
include:
# Also test on macOS and Windows using the latest Python 3
- os: macos-latest
python-version: 3.11 # Return to 3.x after resolution of https://github.com/RDFLib/pySHACL/issues/212
python-version: 3.12 # Return to 3.x after resolution of https://github.com/RDFLib/pySHACL/issues/212
- os: windows-2019
python-version: 3.11 # Return to 3.x after resolution of https://github.com/RDFLib/pySHACL/issues/212
python-version: 3.12 # Return to 3.x after resolution of https://github.com/RDFLib/pySHACL/issues/212

steps:
- uses: actions/checkout@v4
Expand Down
29 changes: 21 additions & 8 deletions sbol_utilities/sbol3_sbol2_conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ def _convert_identified(self, obj3: sbol3.Identified, obj2: sbol2.Identified):
obj2.description = self._value_or_property(obj3, obj3.description, 'http://purl.org/dc/terms/description')
obj2.wasDerivedFrom = obj3.derived_from
obj2.wasGeneratedBy = obj3.generated_by

# Add version to identity
if obj3.sbol2_version:
obj2.identity = obj2.identity + "/" + obj3.sbol2_version
else:
obj2.identity = obj2.identity + "/1"

# Turn measures into extension properties
if obj3.measures:
raise NotImplementedError('Conversion of measures from SBOL3 to SBOL2 not yet implemented')
Expand Down Expand Up @@ -341,6 +348,11 @@ def _convert_toplevel(self, obj2: sbol2.TopLevel, obj3: sbol3.TopLevel):
self._convert_identified(obj2, obj3)
obj3.attachments = [a.identity for a in obj2.attachments]

def _sbol3_identity(self, obj2: sbol2.Identified):
if obj2.version and obj2.identity.endswith("/" + obj2.version):
return obj2.identity[:-len("/" + obj2.version)]
return obj2.identity

def _sbol3_namespace(self, obj2: sbol2.TopLevel):
# If a namespace is explicitly set, that takes priority
if BACKPORT3_NAMESPACE in obj2.properties:
Expand All @@ -350,15 +362,16 @@ def _sbol3_namespace(self, obj2: sbol2.TopLevel):
f'but was {namespaces}')
return namespaces[0]
# Check if the object starts with any of the provided namespaces
for namespace in self.namespaces:
if obj2.identity.startswith(namespace):
return namespace
if self.namespaces:
for namespace in self.namespaces:
if obj2.identity.startswith(namespace):
return namespace
# Otherwise, use default behavior
return None

def visit_activity(self, act2: sbol2.Activity):
# Make the Activity object and add it to the document
act3 = sbol3.Activity(act2.identity, namespace=self._sbol3_namespace(act2),
act3 = sbol3.Activity(self._sbol3_identity(act2), namespace=self._sbol3_namespace(act2),
start_time=act2.startedAtTime, end_time=act2.endedAtTime)
self.doc3.add(act3)
# Convert child objects after adding to document
Expand Down Expand Up @@ -386,7 +399,7 @@ def visit_attachment(self, a: sbol2.Attachment):
def visit_collection(self, coll2: sbol2.Collection):
# Priority: 1
# Make the Collection object and add it to the document
coll3 = sbol3.Collection(coll2.identity, members=coll2.members)
coll3 = sbol3.Collection(self._sbol3_identity(coll2), members=coll2.members)
self.doc3.add(coll3)
# Map over all other TopLevel properties and extensions not covered by the constructor
self._convert_toplevel(coll2, coll3)
Expand All @@ -406,7 +419,7 @@ def visit_component_definition(self, cd2: sbol2.ComponentDefinition):
sbol2.BIOPAX_COMPLEX: sbol3.SBO_NON_COVALENT_COMPLEX}
types3 = [type_map.get(t, t) for t in cd2.types]
# Make the Component object and add it to the document
cp3 = sbol3.Component(cd2.identity, types3, namespace=self._sbol3_namespace(cd2),
cp3 = sbol3.Component(self._sbol3_identity(cd2), types3, namespace=self._sbol3_namespace(cd2),
roles=cd2.roles, sequences=cd2.sequences)
self.doc3.add(cp3)
# Convert the Component properties not covered by the constructor
Expand Down Expand Up @@ -479,7 +492,7 @@ def visit_generic_location(self, a: sbol2.GenericLocation):
def visit_implementation(self, imp2: sbol2.Implementation):
# Priority: 1
# Make the Implementation object and add it to the document
imp3 = sbol3.Implementation(imp2.identity, namespace=self._sbol3_namespace(imp2), built=imp2.built)
imp3 = sbol3.Implementation(self._sbol3_identity(imp2), namespace=self._sbol3_namespace(imp2), built=imp2.built)
self.doc3.add(imp3)
# Map over all other TopLevel properties and extensions not covered by the constructor
self._convert_toplevel(imp2, imp3)
Expand Down Expand Up @@ -527,7 +540,7 @@ def visit_sequence(self, seq2: sbol2.Sequence):
sbol2.SBOL_ENCODING_SMILES: sbol3.SMILES_ENCODING}
encoding3 = encoding_map.get(seq2.encoding, seq2.encoding)
# Make the Sequence object and add it to the document
seq3 = sbol3.Sequence(seq2.identity, namespace=self._sbol3_namespace(seq2),
seq3 = sbol3.Sequence(self._sbol3_identity(seq2), namespace=self._sbol3_namespace(seq2),
elements=seq2.elements, encoding=encoding3)
self.doc3.add(seq3)
# Map over all other TopLevel properties and extensions not covered by the constructor
Expand Down
Loading