Open rpgoldman opened 4 years ago
I think the documentation is misleading. All of the bullets under what appears to be the constructor are really the attributes of the class, not the arguments to a constructor.
Try something like this:
>>> sbol.setHomespace('https://hub.sd2e.org/user/sd2e/design')
>>> display_id = 'beta_estradiol_stimulates_r3_gRNA'
>>> inter = sbol.Interaction(sbol.SBOL_INTERACTION, display_id, sbol.SBO_STIMULATION)
>>> inter.name = 'BE stimulates r3_gRNA_Gene'
>>>
>>>
>>> inter.identity
'https://hub.sd2e.org/user/sd2e/design/Interaction/beta_estradiol_stimulates_r3_gRNA/1'
>>> inter.displayId
'beta_estradiol_stimulates_r3_gRNA'
>>> inter.name
'BE stimulates r3_gRNA_Gene'
>>> inter.types
['http://identifiers.org/biomodels.sbo/SBO:0000170']
Note that I used sbol.SBO_STIMULATION
instead of the raw URI. This avoids typos, and makes the intent clearer to those who are reading the code and are not in the know about the various biomodels.so.
Let us know if that gets you unstuck, or if you have more questions.
Thanks, @tcmitchell -- that's just what I needed.
Note that at least in the numpy style, it's considered ok to add docs for the initialization method to the class doc string. So just adding a Parameters
section to that doc string would really help.
It seems odd that we need to pass sbol.SBOL_INTERACTION
to the constructor for Interaction
-- shouldn't it know that it's an interaction?
Anyway, yes, this has me at least partially unstuck! Thanks again.
Note that at least in the numpy style, it's considered ok to add docs for the initialization method to the class doc string. So just adding a Parameters section to that doc string would really help.
I agree. But the documentation that I think you're reading (https://pysbol2.readthedocs.io/en/latest/API.html#sbol.libsbol.Interaction) is derived from C++ code, not from Python docstrings. So it's not quite so simple with the pySBOL library. As the pure python version reaches maturity, we hope things like this are a little easier.
It seems odd that we need to pass sbol.SBOL_INTERACTION to the constructor for Interaction -- shouldn't it know that it's an interaction?
I agree. I have a slightly different case with the Implementation
class that similarly requires a type_uri as the first argument to the constructor. It's on my list of things to ask @bbartley. I don't know why some classes require this and some (ComponentDefinition, ModuleDefinition) do not. I'll bet there's a reason, so we'll have to have @bbartley weigh in on this aspect.
In order to get me unstuck, would it be possible to assemble a cheat sheet of initialization args? If it helps, I'm only concerned right now with adding enough extra stuff to add a stimulation relationship between a chemical and a gene. So I note that would require only a few entries for the cheat sheet for now. Thanks!
I'd be happy to give that a try. I'm just source diving in the C++ and then experimenting in a Python interpreter. Your explanation does not give me enough info to work from. I do not possess biological knowledge. If you pass along class names that you're having trouble with, I can give it a try.
Well, that will be the blind leading the one-eyed! 😉
Seriously, I think what I need is to make a Participation. I believe the participations are all nested inside the Interaction.
Inside the Participation, I need to put a FunctionalComponent. I think (hope) these three are enough to do the job for me.
Here is the relevant bit of the C++ Participant class:
/// @param uri A full URI including a scheme, namespace, and identifier. If SBOLCompliance configuration is enabled, then this argument is simply the displayId for the new object and a full URI will automatically be constructed.
/// @param participant A reference to the participating FunctionalComponent in the parent Interaction
Participation(std::string uri = "example", std::string participant = "", std::string version = VERSION_STRING)
And here's the relevant bit of C++ for FunctionalComponent:
/// Construct a FunctionalComponent. If operating in SBOL-compliant mode, use ModuleDefinition::functionalComponents::create instead.
/// @param A full URI including a scheme, namespace, and identifier. If SBOLCompliance configuration is enabled, then this argument is simply the displayId for the new object and a full URI will automatically be constructed.
/// @param definition A URI referring to the ComponentDefinition that defines this instance
/// @param access Flag indicating whether the FunctionalComponent can be referred to remotely by a MapsTo
/// @param direction The direction property specifies whether a FunctionalComponent serves as an input, output, both, or neither for its parent ModuleDefinition object
/// @param version An arbitrary version string. If SBOLCompliance is enabled, this should be a Maven version string of the form "major.minor.patch".
FunctionalComponent(std::string uri = "example", std::string definition = "", std::string access = SBOL_ACCESS_PUBLIC, std::string direction = SBOL_DIRECTION_NONE, std::string version = VERSION_STRING)
I think your best bet is to create both with a shortened URI as in my Interaction example above, and then set values on attributes after that. You can experiment with setting things up in the constructor if that's what you prefer. Those arguments should be there for convenience, I don't believe any of the parameters are required.
Here's some quick Python to demonstrate that the constructor args are all optional:
>>> import sbol
>>> sbol.setHomespace('https://hub.sd2e.org/user/sd2e/design')
>>>
>>> p = sbol.Participation()
>>> p.identity
'https://hub.sd2e.org/user/sd2e/design/Participation/example/1'
>>> p = sbol.Participation('my_participation')
>>> p.identity
'https://hub.sd2e.org/user/sd2e/design/Participation/my_participation/1'
>>>
>>> fc = sbol.FunctionalComponent()
>>> fc.identity
'https://hub.sd2e.org/user/sd2e/design/FunctionalComponent/example/1'
>>> fc = sbol.FunctionalComponent('my_func_comp')
>>> fc.identity
'https://hub.sd2e.org/user/sd2e/design/FunctionalComponent/my_func_comp/1'
>>>
Follow-up question -- I see that I need to add these entities to the Document
object: they don't get added automatically.
That is straightforward for my new ModuleDefinition
, which I add with Document.addModuleDefinition
per the docs: " if the user wishes to write out a file with all the information contained in their object, they must first add it to the Document. This is done using add methods. The names of these methods follow a simple pattern, simply “add” followed by the type of object."
But what do I do about Interaction
and Participation
definitions? There are no corresponding add methods? I thought maybe they should use addComponentDefinition
, but:
>>> issubclass(sbol.Interaction, sbol.ComponentDefinition)
False
>>> issubclass(sbol.Participation, sbol.ComponentDefinition)
False
I looked at the SBOL spec, and a Participation
seems to be top level -- its only parent is Identified
.
if not, how do I add them? Or is it sufficient to add just the ModuleDefinition
, and assume that all these properties will be carried along?
Thanks!
Hi @rpgoldman,
Note that Participation
is not TopLevel
:
>>> issubclass(sbol.Participation, sbol.TopLevel)
False
You don't add a Participation
to a Document
directly...you add it to a parent Interaction
. There are two alternative ways to do this:
>>> i = Interaction('i')
>>> p1 = i.participations.create('p1')
or:
>>> i = Interaction('i')
>>> p1 = Participation('p1')
>>> i.participations.add(p1)
Hope that helps!
@bbartley Sorry: one more -- do I need to add the parent Interaction
? And if so, how is this to be done? Presumably since it's not top level, either, Interaction
also does not need to be added? That does not seem to work for me. In my code snippet (see Slack, since this isn't my data to post to GitHub), I create the interaction, and add it to the ModuleDefinition
, but it does not appear in the resulting XML file, although the containing ModuleDefinition
does appear.
Use:
module_definition.interactions.add(i)
@bbartley I did this:
module_def.interactions = [inter]
Do you think that's the problem? And, if so, maybe pySBOL should make it an error if someone tries to set the interactions in this way.
I tried to construct an
Interaction
using the documented API, and got this error:I tried a few modifications, treating the URI (
identity
) andtypes
as positional, instead of keyword, but no dice.