SynBioDex / pySBOL

SWIG-Python wrappers implementing SBOL 2.2
Apache License 2.0
25 stars 8 forks source link

setAnnotation works only in some versions #100

Open dashaveraksa opened 5 years ago

dashaveraksa commented 5 years ago

I am trying to add annotations to FunctionalComponents and I am able to do so in pySBOL version 2.3.0.post10 but when I try to do it in 2.3.0.post20 or 2.3.1.post0 I get a LookupError. Here is the code I am using: valueURI = temp.identity + '#hasNumericalValue'
temp.setAnnotation(valueURI,stringval)

where 'temp' is my FunctionalComponent and 'stringval' is the string version of the value I am trying to add as an annotation. This value represents a numerical measurement. Here is the error I am getting when using 2.3.0.post20 or 2.3.1.post0:

Traceback (most recent call last): File "experimentdnaexcel.py", line 198, in temp.setAnnotation(valueURI,stringval) File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sbol/libsbol.py", line 2905, in setAnnotation return _libsbol.SBOLObject_setAnnotation(self, property_uri, val) LookupError: http://bu.edu/dasha/JHT10_sample_5F0S/pBW465/1#hasNumericalValue not contained in this object.

Am I setting the annotations incorrectly? It is strange because the code works correctly in the older version. Any help would be appreciated.

bbartley commented 5 years ago

@dashaveraksa it looks like this probably got broken in the course of something else getting fixed. In any case, a different, but actually better way to add annotations is like this:

>>> fc.test = FloatProperty(fc, 'http://bu.org/dasha#hasNumericalValue', '0', '1')
>>> fc.test = 10.0
>>> fc.test
10.0

(There is also an IntProperty)

There are all kinds of fancy tricks you can play with Property objects, such as define a new subclass of FunctionalComponent that behaves like the base class, but with new extension attributes like this added.

The arguments '0' and '1' specify cardinality for the property, in this case indicating that the property can have zero or one values. (Other common options are '1' and '1' for properties that are required to have a value, and '0' and '*' for properties that contain a list of values).

Also, the property URI should not be formed out of the identity of the object. In this case, it should most like just be 'http://bu.edu/dasha'

dashaveraksa commented 5 years ago

@bbartley Thank you for responding! However, I tried to use FloatProperty in the same way you have shown and although there were no errors, the values I added to each FunctionalComponenent did not appear in the XML file and by extension in SynBioHub when I uploaded the file.

Also, I want to create a lot of annotations/properties with the same name, but for different FunctionalComponents--since they all need to have a unique URI, how can I form the property URI without referencing the identity of each object that I am creating the annotation/property for?

bbartley commented 5 years ago

Following is a more comprehensive example...

A couple of things to keep in mind. If you don't set a value to the property first, it won't show up in the serialization. Note in the code below that I set the property value to 10. If it isn't set, then you won't see the property in the XML.

Secondly, the second argument in the FloatProperty constructor is not a URI reference to the object you are annotating. Rather, it is an RDF identity for the property that controls how the property appears when serializeed as XML. The namespace 'http://examples.org' is the XML extension namespace, and '#hasNumericalValue' is the local name for the XML property. This property URI should remain consistent and constant for all FunctionalComponents you are annotating. Please inspect the following serialization examples, you should get a better idea how this URI controls XML serialization:

>>> doc = Document()
>>> md = doc.moduleDefinitions.create('md')
>>> fc = md.functionalComponents.create('fc')
>>> fc.hasNumericalValue = FloatProperty(fc, 'http://examples.org#hasNumericalValue', '0', '1')
>>> fc.hasNumericalValue = 10.0
>>> print(doc.writeString())
<?xml version="1.0" encoding="utf-8"?>
<rdf:RDF xmlns:dcterms="http://purl.org/dc/terms/"
   xmlns:prov="http://www.w3.org/ns/prov#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:sbol="http://sbols.org/v2#"
   xmlns:sys-bio="http://sys-bio.org#">
  <sbol:ModuleDefinition rdf:about="http://examples.org/ModuleDefinition/md/1">
    <sbol:displayId>md</sbol:displayId>
    <sbol:functionalComponent>
      <sbol:FunctionalComponent rdf:about="http://examples.org/ModuleDefinition/md/fc/1">
        <ns1:hasNumericalValue xmlns:ns1="http://examples.org#">10.000000</ns1:hasNumericalValue>
        <sbol:access rdf:resource="http://sbols.org/v2#public"/>
        <sbol:direction rdf:resource="http://sbols.org/v2#none"/>
        <sbol:displayId>fc</sbol:displayId>
        <sbol:persistentIdentity rdf:resource="http://examples.org/ModuleDefinition/md/fc"/>
        <sbol:version>1</sbol:version>
      </sbol:FunctionalComponent>
    </sbol:functionalComponent>
    <sbol:persistentIdentity rdf:resource="http://examples.org/ModuleDefinition/md"/>
    <sbol:version>1</sbol:version>
  </sbol:ModuleDefinition>
</rdf:RDF>

>>> doc.addNamespace('http://examples.org#', 'examples')
>>> print(doc.writeString())
<?xml version="1.0" encoding="utf-8"?>
<rdf:RDF xmlns:dcterms="http://purl.org/dc/terms/"
   xmlns:examples="http://examples.org#"
   xmlns:prov="http://www.w3.org/ns/prov#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:sbol="http://sbols.org/v2#"
   xmlns:sys-bio="http://sys-bio.org#">
  <sbol:ModuleDefinition rdf:about="http://examples.org/ModuleDefinition/md/1">
    <sbol:displayId>md</sbol:displayId>
    <sbol:functionalComponent>
      <sbol:FunctionalComponent rdf:about="http://examples.org/ModuleDefinition/md/fc/1">
        <examples:hasNumericalValue>10.000000</examples:hasNumericalValue>
        <sbol:access rdf:resource="http://sbols.org/v2#public"/>
        <sbol:direction rdf:resource="http://sbols.org/v2#none"/>
        <sbol:displayId>fc</sbol:displayId>
        <sbol:persistentIdentity rdf:resource="http://examples.org/ModuleDefinition/md/fc"/>
        <sbol:version>1</sbol:version>
      </sbol:FunctionalComponent>
    </sbol:functionalComponent>
    <sbol:persistentIdentity rdf:resource="http://examples.org/ModuleDefinition/md"/>
    <sbol:version>1</sbol:version>
  </sbol:ModuleDefinition>
</rdf:RDF>
jakebeal commented 5 years ago

BTW, @bbartley : a key goal of these annotations is to add Measure information. Do you have a recommended example of doing that with pySBOL?

cjmyers commented 5 years ago

Is Measure even supported yet in pySBOL?

On Jun 21, 2019, at 11:33 AM, Jacob Beal notifications@github.com wrote:

BTW, @bbartley https://github.com/bbartley : a key goal of these annotations is to add Measure information. Do you have a recommended example of doing that with pySBOL?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/SynBioDex/pySBOL/issues/100?email_source=notifications&email_token=AA2YH524DDGXELBCVTHB3NTP3UGGFA5CNFSM4HZB4DOKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODYJC6BI#issuecomment-504508165, or mute the thread https://github.com/notifications/unsubscribe-auth/AA2YH56FETOTXDQJ6NAHLWDP3UGGFANCNFSM4HZB4DOA.

bbartley commented 5 years ago

It's implemented in the source code but I haven't yet generated any precompiled packages for distribution.

dashaveraksa commented 5 years ago

Thank you for explaining the RDF identity, I get it now.

As for the annotations issue, I think I have figured out what the problem is--I was using 2.3.0.post10, where setAnnotations works but running the exact example you showed above does not put the annotation in the XML file, at least on my computer. I tried it on 2.3.1.post0 and it appeared just as your example above. I then tried it on 2.3.0.post15 and it again did not show.

Here is what I am seeing, using 2.3.0.post10:

>>> doc = Document()
>>> md = doc.moduleDefinitions.create('md')
>>> fc = md.functionalComponents.create('fc')
>>> fc.hasNumericalValue = FloatProperty(fc, 'http://examples.org#hasNumericalValue', '0', '1')
>>> fc.hasNumericalValue = 10.0
>>> print(doc.writeString())
<?xml version="1.0" encoding="utf-8"?>
<rdf:RDF xmlns:dcterms="http://purl.org/dc/terms/"
   xmlns:prov="http://www.w3.org/ns/prov#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:sbol="http://sbols.org/v2#"
   xmlns:sys-bio="http://sys-bio.org#">
  <sbol:ModuleDefinition rdf:about="http://examples.org/ModuleDefinition/md/1.0.0">
    <sbol:displayId>md</sbol:displayId>
    <sbol:functionalComponent>
      <sbol:FunctionalComponent rdf:about="http://examples.org/ModuleDefinition/md/fc/1.0.0">
        <sbol:access rdf:resource="http://sbols.org/v2#public"/>
        <sbol:direction rdf:resource="http://sbols.org/v2#none"/>
        <sbol:displayId>fc</sbol:displayId>
        <sbol:persistentIdentity rdf:resource="http://examples.org/ModuleDefinition/md/fc"/>
        <sbol:version>1.0.0</sbol:version>
      </sbol:FunctionalComponent>
    </sbol:functionalComponent>
    <sbol:persistentIdentity rdf:resource="http://examples.org/ModuleDefinition/md"/>
    <sbol:version>1.0.0</sbol:version>
  </sbol:ModuleDefinition>
</rdf:RDF>