1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
<HTML>
<HEAD>
<TITLE>pyOpenMS (Python bindings)</TITLE>
<LINK HREF="doxygen.css" REL="stylesheet" TYPE="text/css">
<LINK HREF="style_ini.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<A href="index.html">Home</A> ·
<A href="classes.html">Classes</A> ·
<A href="annotated.html">Annotated Classes</A> ·
<A href="modules.html">Modules</A> ·
<A href="functions_func.html">Members</A> ·
<A href="namespaces.html">Namespaces</A> ·
<A href="pages.html">Related Pages</A>
<HR style="height:1px; border:none; border-top:1px solid #c0c0c0;">
<!-- Generated by Doxygen 1.8.5 -->
</div><!-- top -->
<div class="header">
<div class="headertitle">
<div class="title">pyOpenMS (Python bindings) </div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><h1 style="margin-top:40px; border-top:4px solid grey; text-align:left;">Introduction</h1>
<p>PyOpenMS offers Python bindings to a large part of the OpenMS API.</p>
<h1 style="margin-top:40px; border-top:4px solid grey; text-align:left;">Build Instructions</h1>
<p>In order to configure and build pyOpenMS successfully, you will need to install the following :</p>
<ol>
<li>
<p class="startli">Install python (preferably, 2.7 but it may run also run with Python 2.6) </p>
<p class="endli"></p>
</li>
<li>
<p class="startli">On windows: you need the 64 bit C++ compiler from Visual Studio 2008. This is important, else you get a different clib than python 2.7 is built with, and pyopenms will crash on import. </p>
<p class="endli"></p>
</li>
<li>
<p class="startli">Install setuptools, see: <a href="https://pypi.python.org/pypi/setuptools">https://pypi.python.org/pypi/setuptools</a> </p>
<p class="endli"></p>
</li>
<li>
<p class="startli">Install pip and using it, install other required Python modules</p>
<div class="fragment"><div class="line">$ easy_install pip</div>
<div class="line">$ pip install autowrap</div>
<div class="line">$ pip install nose</div>
</div><!-- fragment --><p>If Cython doesn't get installed, install it with </p>
<div class="fragment"><div class="line">$ easy_install cython</div>
</div><!-- fragment --><p>Note that when using pip without root permissions, you have to add a path prefix: –install-option="--prefix=/path/to/local/python/" </p>
<p class="endli"></p>
</li>
<li>
<p class="startli">Install numpy:</p>
<ul>
<li>on debian/ubuntu, install the package "python-numpy"</li>
<li>on 64 bit win 7: get it from <a href="http://www.lfd.uci.edu/~gohlke/pythonlibs/#numpy">http://www.lfd.uci.edu/~gohlke/pythonlibs/#numpy</a> </li>
</ul>
<p class="endli"></p>
</li>
<li>
<p class="startli">Configure OpenMS with pyOpenMS: execute cmake as usual, but with parameters "-D PYOPENMS=ON". </p>
<p>On windows add: "-D CMAKE_BUILD_TYPE=Release" as the standard python27.dll is built in release mode. </p>
<p></p>
<p class="endli"></p>
</li>
<li>
<p class="startli">Build pyOpenMS (now there should be pyopenms specific build targets):</p>
<div class="fragment"><div class="line">$ make pyopenms</div>
</div><!-- fragment --><p>on linux: ensure that the libOpenMS.so is in your $LD_LIBRARY_PATH (it needs to be accessible for Python) </p>
<p class="endli"></p>
</li>
<li>
<p class="startli">Run the Python specific tests to make sure that everything went well</p>
<div class="fragment"><div class="line">$ cd pyOpenMS</div>
<div class="line">$ run_nose.py</div>
</div><!-- fragment --><p>run mem leak test:</p>
<div class="fragment"><div class="line">$ run_memleaks.py</div>
</div><!-- fragment --> <p class="endli"></p>
</li>
<li>
<p class="startli">Optionally: if you want to install locally:</p>
<div class="fragment"><div class="line">$ python setup.py install</div>
</div><!-- fragment --><p> If you want to build Python installers:</p>
<div class="fragment"><div class="line">$ make pyopenms_bdist_egg</div>
</div><!-- fragment --><p>or</p>
<div class="fragment"><div class="line">$ make pyopenms_bdist</div>
</div><!-- fragment --><p>you find the built installer files in pyOpenMS/dist </p>
<p class="endli"></p>
</li>
</ol>
<h1 style="margin-top:40px; border-top:4px solid grey; text-align:left;">Wrapping Workflow and wrapping new Classes</h1>
<h2 style="margin-top:40px; border-top:4px solid grey; text-align:left;">How pyOpenMS wraps Python classes</h2>
<p>General concept of how the wrapping is done:</p>
<ul>
<li>Step 1: The author declares which classes and which functions of these classes s/he wants to wrap (expose to Python). This is done by writing the function declaration in a file in the pxds/ folder.</li>
<li>Step 2: The Python tool "autowrap" (developed for this project) creates the wrapping code automatically from the function declaration - see <a href="https://github.com/uweschmitt/autowrap">https://github.com/uweschmitt/autowrap</a> for an explanation of the autowrap tool. Since not all code can be wrapped automatically, also manual code can be written in the addons/ folder. Autowrap will create an output file at pyopenms/pyopenms.pyx</li>
<li>Step 3: Cython translates the pyopenms/pyopenms.pyx to Cpp code at pyopenms/pyopenms.cpp</li>
<li>Step 4: A compiler compiles the Cpp code to a Python module which is then importable in Python with "import pyopenms"</li>
</ul>
<p>Maintaining existing wrappers: If the C++ API is changed, then pyOpenMS will not build any more. Thus, find the corresponding file in the pyOpenMS/pxds/ folder and adjust the function declaration accordingly.</p>
<h2 style="margin-top:40px; border-top:4px solid grey; text-align:left;">How to wrap new classes</h2>
<p>To wrap a new OpenMS class: Create a new "pxd" file in the folder "./pxds". As a small example, look at the CVTerm.pxd to get you started. Start with the following structure:</p>
<div class="fragment"><div class="line">from xxx cimport *</div>
<div class="line">cdef <span class="keyword">extern</span> from <span class="stringliteral">"<OpenMS/path/to/header.h>"</span> <span class="keyword">namespace </span>"OpenMS":</div>
<div class="line"></div>
<div class="line"> cdef cppclass ClassName(DefaultParamHandler):</div>
<div class="line"><span class="preprocessor"> # wrap-inherits:</span></div>
<div class="line"><span class="preprocessor"></span><span class="preprocessor"> # DefaultParamHandler</span></div>
<div class="line"><span class="preprocessor"></span></div>
<div class="line"> ClassName() nogil except +</div>
<div class="line"> ClassName(ClassName) nogil except +</div>
</div><!-- fragment --><ul>
<li>make sure to use "ClassName:" instead of "ClassName(DefaultParamHandler)" to wrap a class that does not inherit from another class and also remove the two comments below that line.</li>
<li>always use "cimport" and not Python "import"</li>
<li>always add default constructor AND copy constructor to the code (note that the C++ compiler will add a default copy constructur to any class, so there is always one if it is not declared, see <a href="http://www.cplusplus.com/articles/y8hv0pDG/">http://www.cplusplus.com/articles/y8hv0pDG/</a> "The
implicit copy constructor does a member-wise copy of the source object.")</li>
<li>to expose a function to Python, copy the signature to your pxd file, e.g. "DataValue getValue()" and make sure you "cimport" all corresponding classes. Replace std::vector with vector from libcpp.vector (see for example PepXMLFile.pxd)</li>
<li>Remember to include a copy constructor (even if none was declared in the C++ header file) since Cython will need it for certain oprations. Otherwise you might see error messages like "item0.inst = shared_ptr[_ClassName](new _ClassNAme(deref(it_terms))) Call with wrong number of arguments"</li>
</ul>
<p>Further considerations and limitations:</p>
<ul>
<li>Inheritance: there are some limitations, see for example Precursor.pxd</li>
<li>Reference: arguments by reference may be copied under some circumstances. For example, if they are in an array then not the original argument is handed back, so comparisons might fail. Also, simple Python types like int, float etc cannot be passed by reference.</li>
<li>operator+=: see for example AASequence.iadd in AASequence.pxd</li>
<li>operator==, !=, <=, <, >=, > are wrapped automatically</li>
<li>Iterators: some limitations apply, see MSExperiment.pxd for an example</li>
<li>copy-constructor becomes __copy__ in Python</li>
<li>shared pointers: is handled automatically, check DataAccessHelper using shared_ptr[Spectrum]. Use "from smart_ptr cimport shared_ptr" as import statement</li>
</ul>
<p>These hints can be given to autowrap (also check the autowrap documentation):</p>
<ul>
<li>wrap-ignore: is a hint for autowrap to not wrap the function (but the declaration might still be important for Cython to know about)</li>
<li>wrap-as - see for example AASequence ":"</li>
<li>wrap-iter-begin, wrap-iter-end (see ConsensusMap.pxd)</li>
<li>wrap-instances - for templated classes (see MSSpectrum.pxd)</li>
<li>wrap-attach: enums, static methods (see for example VersionInfo.pxd)</li>
<li>wrap-upper-limit:size or size() (see MSSpectrum.pxd)</li>
</ul>
<h3 style="margin-top:40px; border-top:4px solid grey; text-align:left;">Wrapping code yourself in ./addons </h3>
<p>Not all code can be wrapped automatically (yet). Place a file with the same (!) name in the addons filder (e.g. myClass.px in pxds/ and myClass.pyx in addons) and leave two lines empty on the top (this is important). Start with 4 spaces of indent and write your additional wrapper functions, adding a wrap-ignore comment to the pxd file. For some examples, look into the addons folder:</p>
<ul>
<li>IDRipper.pyx<ul>
<li>for a reference for both input and output of a complex STL construct (map< String, pair<vector<>, vector<> > )</li>
</ul>
</li>
<li>MSQuantifications.pyx<ul>
<li>for a vector< vector< pair <String,double > > > as input in registerExperiment</li>
<li>for a map< String, Ratio> in getRatios to get returned</li>
</ul>
</li>
<li>QcMLFile.pyx<ul>
<li>for a map< String, map< String,String> > as input</li>
</ul>
</li>
<li>SequestInfile.pyx<ul>
<li>for a map< String, vector<String> > to get returned</li>
</ul>
</li>
<li>Attachment.pyx<ul>
<li>for a vector< vector<String> > to get returned</li>
</ul>
</li>
</ul>
<p>Make sure that you _always_ declare your objects (all C++ and all Cython objects need to be declared) using cdef Type name. Otherwise you get "Cannot
convert ... to Python object" errors. </p>
</div></div><!-- contents -->
<HR style="height:1px; border:none; border-top:1px solid #c0c0c0;">
<TABLE width="100%" border="0">
<TR>
<TD><font color="#c0c0c0">OpenMS / TOPP release 1.11.1</font></TD>
<TD align="right"><font color="#c0c0c0">Documentation generated on Thu Nov 14 2013 11:19:25 using doxygen 1.8.5</font></TD>
</TR>
</TABLE>
</BODY>
</HTML>
|