Low-level C++ API bindings¶
Low level module containing Sip bindings of Anatomist C++ API.
Introduction¶
This module is mostly bindings to the C++ library of Anatomist. A few classes have been slightly modified or rewritten, either to hide garbage or to appear more pythonic.
For typical use, this module will not be called directly but throught general API. But it can be needed for using advanced features.
The main entry point is the Anatomist
class which must be instantiated before any operation can be performed.
>>> import anatomist.cpp as anatomist
>>> a = anatomist.Anatomist()
Note that instantiating Anatomist also instantiates the Qt QApplication, but does not run the Qt event loop, so python interactive shells are still accessible after that operation, but the GUI is frozen until the event loop is executed, using the following PyQt code:
>>> # from PyQt4 import Qt
>>> # or, to switch to the correct Qt implementation and bindings (Qt4/Qt5)
>>> from soma.qt_gui.qt_backend import Qt
>>> Qt.qApp.exec_loop()
but then the loop does not return until the GUI application is over, so you should start it at the end of your code.
Another comfortable alternative to the GUI loop problem in interactive
python shells is to use IPython with the
option --gui=qt
: IPython is an interactive python shell with many
improvements, and which can run in a different thread than the GUI, so that
the GUI can run without hanging the shell.
Contrarily to the Qt application, Anatomist can be instantiated multiple times (it is not a singleton, but contains a singleton).
In addition to providing bindings to the Anatomist C++ API, the anatomist module also loads some python modules in anatomist: every python module found in the following locations are loaded:
os.path.join(str(anatomist.Anatomist().anatomistSharedPath()), 'python_plugins')
os.path.join(str(anatomist.Anatomist().anatomistHomePath()), 'python_plugins')
Main concepts¶
There are many pieces in Anatomist library, but a few are really needed to begin with.
- the Anatomist application, the L{Anatomist} class instance, is responsible for many global variables, the application state, and the startup procedure (including plugins loading). The application is used internally in many functions.
- objects:
AObject
class and subclasses - windows:
AWindow
class and subclasses - the commands processor: a singleton
Processor
instance obtained via the application:Anatomist.theProcessor()
. The processor is a commands interpreter for the rudimentary language of Anatomist. It is also responsible of saving every command executed in the history file$HOME/.anatomist/history.ana
so most of the session can be replayed. Many operations are done via commands and the processor: creating windows, loading objects, displaying them, etc. so this element is probably the most important part of Anatomist. - conversions between AIMS object and Anatomist objects:
AObjectConverter
is here to perform this task.
-
class
anatomist.cpp.
AObjectConverter
¶ Aims / Anatomist objects converter
Only two static methods are useful in this class:
AObjectConverter.anatomist()
converts an AIMS (or possibly other) object into an Anatomist object (AObject
subclass), if possibleAObjectConverter.aims()
converts an Anatomist object to an AIMS object, if possible
Conversions are generally done by wrapping or embedding, or by extracting a reference to an internal object, so objects data are genrally shared between the AIMS and the Anatomist objects layers. This allows internal modification of Anatomist objects data.
After a modification through the Aims (lower level) layer API, modification notification must be issued to the Anatomist layer to update the display of the object in Anatomist. This is generally done via the
AObject.setChanged()
andAObject.notifyObservers()
methods.
-
class
anatomist.cpp.
Command
¶ Commands are the execution units of the
Processor
.Commands are used as subclasses of
Command
. They can be built either on the fly by the programmer, or using the commands factory via theProcessor.execute()
function.Never call
Command.execute()
orCommand.doit()
directly: only the processor will do so. Once built, a command must always be executed by the processor:>>> a = anatomist.Anatomist() >>> c = anatomist.CreateWindowCommand('Axial') >>> a.theProcessor().execute(c)
But in any case there is a more handy shortcut in the higher-level API:
anatomist.base.Anatomist.execute()
Comamnds can be subclassed in Python. To be valid, a new command must define at least the
name()
anddoit()
methods.doit()
will actually do the execution and your program may make it do anything. Later,read()
andwrite()
should also be redefined to allow proper IO for this command (when the commands IO and factory are exported from C++ to python).Command.doit()
receives no parameters (apart fromself
). All execution arguments must be set in the command itself upon construction (either by the constructor or by setting some instance variables).One important parameter which a command would often use is the
CommandContext
, which specifies some IO streams for output printing and communication with external programs, and an identifiers set used to name and identify objects (in a general meaning: including windows etc.) through this IO streams.