SynBioDex / pySBOL2

A pure Python implementation of the SBOL standard.
Apache License 2.0
20 stars 6 forks source link

Java Validation error when creating an interaction and adding it to a document with pySBOL2 #439

Closed manulera closed 4 months ago

manulera commented 4 months ago

While working on https://github.com/SynBioDex/SBOL-utilities/issues/249 and https://github.com/SynBioDex/SBOL-utilities/issues/248 I encountered this error. I think this is how I would create an interaction in a document in SBOL2.

import sbol2
import tyto

doc2 = sbol2.Document()

component2 = sbol2.ComponentDefinition('hello')
subcomponent2 = sbol2.FunctionalComponent(definition=component2.identity)

participation2 = sbol2.Participation(participant=subcomponent2)
participation2.addRole(sbol2.SBO_REACTANT)

interaction2 = sbol2.Interaction(
    interaction_type=tyto.SBO.cleavage
)

interaction2.participations.add(participation2)
interaction2_component = sbol2.ModuleDefinition('hello2')
interaction2_component.interactions.add(interaction2)
interaction2_component.functionalComponents.add(subcomponent2)

doc2.add(interaction2_component)
doc2.add(component2)

doc2.validate()

However, this seems to give a java exception in the validator:

Invalid. Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.net.URI
        at org.sbolstandard.core2.SBOLReader.parseModuleDefinition(SBOLReader.java:5736)
        at org.sbolstandard.core2.SBOLReader.readTopLevelDocs(SBOLReader.java:1072)
        at org.sbolstandard.core2.SBOLReader.read(SBOLReader.java:745)
        at org.sbolstandard.core2.SBOLReader.read(SBOLReader.java:632)
        at org.sbolstandard.core2.SBOLReader.read(SBOLReader.java:519)
        at org.sbolstandard.core2.SBOLReader.read(SBOLReader.java:444)
        at org.sbolstandard.core2.SBOLReader.read(SBOLReader.java:429)
        at org.sbolstandard.core2.SBOLValidate.validate(SBOLValidate.java:2772)
        at org.sbolstandard.core2.SBOLValidate.main(SBOLValidate.java:3100)

This error comes from here: https://github.com/SynBioDex/libSBOLj/blob/5291cd38f02e74bb23fa37a17ca0167b0f854105/core2/src/main/java/org/sbolstandard/core2/SBOLReader.java#L5736C1-L5737C1

Am I doing something wrong in the python code?

jakebeal commented 4 months ago

There are two problems here that you will face in pySBOL2 that you will not face in pySBOL3:

  1. The child objects must be supplied with locally unique display IDs
  2. The child objects must be added to a TopLevel object (in order to get their full URI) before they are referred to from another child object

Here is equivalent construction code that follows these rules and produces a valid document:

import sbol2
import tyto

doc2 = sbol2.Document()

component2 = sbol2.ComponentDefinition('hello')
subcomponent2 = sbol2.FunctionalComponent('subcomp')
subcomponent2.definition=component2.identity

interaction2_component = sbol2.ModuleDefinition('hello2')
interaction2_component.functionalComponents.add(subcomponent2)

interaction2 = sbol2.Interaction('reaction1', interaction_type=tyto.SBO.cleavage)
interaction2_component.interactions.add(interaction2)

participation2 = sbol2.Participation(uri='reactant1')
participation2.addRole(sbol2.SBO_REACTANT)
participation2.participant=subcomponent2
interaction2.participations.add(participation2)

doc2.add(interaction2_component)
doc2.add(component2)

doc2.validate()
jakebeal commented 4 months ago

I am closing this as resolved since I have provided an answer to the question and code that produces a valid document. If this has not addressed the question sufficiently, please reopen.

manulera commented 4 months ago

Thanks, a followup question for the converter.

To convert from sbol2 to sbol3, where/how do we store the original uri of the sbol2 object in the sbol3 object?

jakebeal commented 4 months ago

We store SBOL2 version information, which doesn't have an equivalent in SBOL3, is saved in an extension property defined at the top of the file: https://github.com/SynBioDex/SBOL-utilities/blob/8a30f7b9fdc0d01b5f1637146e852cf3cc7a1702/sbol_utilities/sbol3_sbol2_conversion.py#L9

We can do the same thing for any child sbol2.persistentIdentity that doesn't match the sbol3.identity automatically assigned by SBOL3.