A list for the developers of CellML tools

Text archives Help


[cellml-dev] CellML API Python bindings issues


Chronological Thread 
  • From: ak.miller at auckland.ac.nz (Andrew Miller)
  • Subject: [cellml-dev] CellML API Python bindings issues
  • Date: Wed, 09 Feb 2011 16:06:45 +1300

On 09/02/11 14:05, Tommy Yu wrote:
> Andrew Miller wrote:
>> Hi Tommy,
>>
>> Would you be able to send me the list of issues you found with the
>> Python bindings that you mentioned at today's meeting that you have
>> written? I'll go through it and see if I can break it down into things
>> to put into individual tracker items.
>>
>> Best wishes,
>> Andrew
>
>
> Hi Andrew,
>
> This is what I have so far (most of it written yesterday), please note this
> disclaimer: I am raising these issues as a spoiled Python programmer, do
> take everything I say with large gains of salt and feel free to give me
> rebuttals and please don't be offended.

Hi Tommy,

I'll go through the list - most of these are as the API is designed; I
think a thin Python wrapper around some of the API functions might
improve functionality.

>
>
> 1) Not high-level enough
>
> - When working with the CellML API, I feel like working with DOM rather
> than CellML. It seems the API just added some CellML extension to the
> DOM rather than dealing directly with CellML concepts, such as a quick
> way to acquire list of connections, links to components, the maths
> within, etc.


The core API is designed primarily to access that structure of the
CellML; extensions provide additional functionality on top of this. Most
of the things you mentioned can be done simply via the API, it just
takes a bit of getting used to the structure:
* Acquire a list of connections:
* if you want all connections in a model document:
Obtain the Model, access the connections attribute, iterate
through connections.
* if you don't want to deal with connections at all, and just
know which variables are the same, use the CeVAS Service.
* Links to components:
* From a connection: you can just do
componentMapping.firstComponent, componentMapping.secondComponent to
fetch the commponents.
* Retrieving the maths: The API doesn't provide a way to extract all
maths yet - mainly because there are only a few special cases where that
is useful.

> - At least this is the case with the model object acquired loaded from
> a URI using the model loader (the model object has many DOM related
> concepts that could be hidden away until I cast it into a DOM document
> object).

You can't cast to a DOM document - instead, queryInterface to
CellMLDOMElement by doing:
cellml_api_CellMLDOMElement(theModel).domElement

This will give you access to the standard W3C DOM element.

>
> 2) Iterators are not really iterators
>
> - Inconsitency in the naming of next methods; a user shouldn't have to
> refer to the documentation for every iterator.

The naming scheme is consistent but uses multiple inheritance to provide
increasingly more specialised methods.

>
> - Example inconsistent names for the various next methods:
>
> - CellML_APISPEC.ExtensionAttributeIterator.nextAttribute
> - CellML_APISPEC.ImportComponentIterator.nextImport
> - They should all just be simply next.

For all element sets, there is a consistent operation on the base called
exactly that, next(), which you can use on any element set. However, it
returns a CellMLElement - if you want something more specialised, you
need to explicitly queryInterface it to what you want.

The nextXXX() operations are provided as syntactic sugar because they do
what next() does, but they also give you the interface you want.

In a statically typed language this is correct and exactly what you
want. In a dynamically typed language, it would be good if you could
just call next() and use it straight away - this would require a change
to the object model to make interfaces discoverable, and a change to the
Python bindings to use interface discovery to ensure that all applicable
interfaces on an object are immediately available for use. Mozilla does
something similar with some of their Javascript bindings to XPCOM.


>
> - Even the method to acquire the iterator is inconsistent, or have
> different iterators?
>
> >>> cbs = CellML_APISPEC.CellMLBootstrap()
> >>> loader = cbs.getmodelLoader()
> >>> model = loader.loadFromURL(url)
> >>> model.getextensionAttributes().iterate()
> <CellML_APISPEC.ExtensionAttributeIterator object at ...>
> >>> model.getimports().iterateImports()
> <CellML_APISPEC.CellMLImportIterator object at ...>
>
> >>> model.getimports().iterate()
> <CellML_APISPEC.CellMLElementIterator object at ...>

As you have found, you can use iterate() on any element set. The
CellMLImportIterator is a more specialised interface -
CellMLElementIterator is the base - you can queryInterface between them.

>
> - Extending on the above example, why am I offered the wrong element
> type when calling the default iterate method?
>
> >>> model.getimports().iterate()
> <CellML_APISPEC.CellMLElementIterator object at ...>
>
> >>> model.getimports().iterateImports()
> <CellML_APISPEC.CellMLImportIterator object at ...>

See above - iterate() is on the base interface, the iterateXXX() methods
are syntactic sugar for obtaining the more specialised elements. If you
prefer, you can use iterate() and queryInterface to the type you want.
This could be improved by providing interface discovery.

>
> - If I want to iterate through the raw element, I should be able to
> cast the object to its parent (more primitive) class and call its
> iterate method.

You don't need to queryInterface or cast to access base interface
operations on a derived interface wrapper - only if you have a wrapper
of the base type and want a wrapper of the derived type.

>
> - While they do their job, they don't work as intended in the Python
> bindings. Or C++, for that matter (not really STL).

The API is written using the XPCOM-like object model, not STL; this
allows it to be accessed from multiple languages automatically, and
imposes a clear memory management model.

> - Even the actual implementation of the API don't use or implement
> iterators according to the standard template library in all cases.
>
> 3) Model loader not re-entrant

The API is not designed to be thread-safe, but it is (supposed to be)
re-entrant - you can call the API from any callbacks out of the API.

However, I recommend loading models into strings and using
loadDocumentFromText() and instantiateFromText() to load the model and
all imports manually (see OpenCell for an example of how to do this),
because it gives you a lot more control over how things are loaded.

> - This makes it impossible to use safely as part of a repository. While
> it probably can be safely be built into a webservice (thus not letting
> it accessing itself), not fixing this issue can result in unintended
> deadlocks of a server process. Workarounds can be done (such as
> forking) but this is never ideal.
>
> 4) Example code includes "Utilities.hxx" which is not installed as part
> of `make install`. People will find this difficult to use if the
> example isn't done correctly.

You can run the tests using "make check" - but I agree that something
needs to be done about Utilities.hxx - it is an internal part of the API
implementation which you don't technically need to use to use the API,
but it has become useful outside of the API internals. It could be
thought of as part of the C++ glue.

Best wishes,
Andrew



  • [cellml-dev] CellML API Python bindings issues, Andrew Miller, 02/09/2011

Archive powered by MHonArc 2.6.18.

Top of page