mozilla

Revision 127033 of Creating a Python XPCOM component

  • Revision slug: Creating_a_Python_XPCOM_component
  • Revision title: Creating a Python XPCOM component
  • Revision id: 127033
  • Created:
  • Creator: Nickolay
  • Is current revision? No
  • Comment /* Preparation */ wording tweak per sheppy

Revision Content

Creating Applications with Mozilla already provides a tutorial for making a simple JavaScript or C++ component (implementing the nsISimple interface), here is how to make the same component in Python using PyXPCOM.

(Note that some details may be missing)

Preparation

The PyXPCOM library is already provided with Mozilla. To use the library, tell Python where it can find the PyXPCOM library. This is probably best done by adding a "mozillalibs.pth" (any name will work) to your Python site packages directory (e.g. "/usr/lib/python2.3/site-packages"), with only one line, the location of the packages you may want to import (the "/dist/bin/python" of your mozilla source).

Then you can

import xpcom

in any Python module (mostly, in your component).

Your copy of Mozilla will need to be able to support Python, although this may require special compilation. It may possible to build the PyXPCOM stuff seperately, but that is not addressed in this document.

To build Mozilla, get and compile the source, with the following options in the .mozconfig file (in the root of your Mozilla source).

. $topsrcdir/browser/config/mozconfig
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/fb-opt-static
ac_add_options --enable-optimize
ac_add_options --disable-debug
ac_add_options --enable-static
ac_add_options --disable-shared
ac_add_options --disable-tests
ac_add_options --disable-short-wchar
ac_add_options --enable-extensions=default,python/xpcom

The two last lines are the most important for this process.

Now, launch the build.

Note: Previous versions of the PyXPCOM library are provided here, although download and use of an old version is not recommended.

Defining the interface

Make a file named "py_simple.idl", to define the interface:

#include "nsISupports.idl"
[scriptable, uuid(2b324e9d-a322-44a7-bd6e-0d8c83d94883)]
interface nsIPySimple : nsISupports
{
    attribute string yourName;
    void write( );
    void change(in string aValue);
};

This is the same as the nsISimple interface used here . Theoretically, because several components can share an interface, the same file could be used.

Pay special attention to types here - Python and JavaScript are both loosely-typed, so it's fairly easy to pass information from one to the other.

Note: There are exceptions; see this discussion for information on the use of string and wstring for unicode transfer. See here for info on describing interfaces, and on which types can be used.

Registring the interface

In the "components" directory, execute :

../xpidl -m typelib -w -v -I /usr/share/idl/mozilla/ nsIPySimple.idl

xpidl will then create nsIPySimple.xpt, which should be placed correctly, (e.g. in the "components" directory).

Implementing the component

Unlike C++, PyXPCOM does much of the work for you.

Make a file named "py_simple.py" for the actual code (again, in the 'components': directory)

from xpcom import components, verbose

class PySimple: #PythonTestComponent
    _com_interfaces_ = components.interfaces.nsIPySimple
    _reg_clsid_ = "{c456ceb5-f142-40a8-becc-764911bc8ca5}"
    _reg_contractid_ = "@mozilla.org/PySimple;1"
    def __init__(self):
        self.yourName = "a default name" # or mName ?

    def __del__(self):
        if verbose:
            print "PySimple: __del__ method called - object is destructing"

    def write(self):
        print self.yourName

    def change(self, newName):
        self.yourName = yourName

Then register your component; the procedure is the same for any component, but will not work if Python components weren't enabled.

To register the component, touch the .autoreg (a hidden file) in the bin directory, or delete xpti.dat. Then, the next time Mozilla starts, it will rebuild the index of components, including any new one in the 'components' directory. It is helpful to then start Mozilla from the command line to see if new components register successfully.

Testing it

To see this work, you will have to start Firefox from the command line, since that'll be where the stuff will be printed out.

External links

Revision Source

<p>
</p><p><a class="external" href="http://books.mozdev.org/html"><i>Creating Applications with Mozilla</i></a> already provides  <a class="external" href="http://books.mozdev.org/html/mozilla-chp-8-sect-2.html">a tutorial</a> for making a simple JavaScript or C++ component (implementing the <code>nsISimple</code> interface), here is how to make the same component in Python using <a href="en/PyXPCOM">PyXPCOM</a>.
</p><p>(Note that some details may be missing)
</p>
<h4 name="Preparation"> Preparation </h4>
<p>The PyXPCOM library is already provided with Mozilla.  To use the library, tell Python where it can find the PyXPCOM library. This is probably best done by adding a "mozillalibs.pth" (any name will work) to your Python site packages directory (e.g. "/usr/lib/python2.3/site-packages"), with only one line, the location of the packages you may want to import (the "/dist/bin/python" of your mozilla source).
</p><p>Then you can 
</p>
<pre class="eval">import xpcom
</pre>
<p>in any Python module (mostly, in your component).
</p><p>Your copy of Mozilla will need to be able to support Python, although this may require special compilation. It may possible to <a class="external" href="http://kb.mozillazine.org/Standalone_PyXPCOM">build the PyXPCOM stuff seperately</a>, but that is not addressed in this document.
</p><p>To build Mozilla, <a href="en/Build"> get and compile the source</a>, with the following  options in the .mozconfig file (in the root of your Mozilla source).
</p>
<pre class="eval">. $topsrcdir/browser/config/mozconfig
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/fb-opt-static
ac_add_options --enable-optimize
ac_add_options --disable-debug
ac_add_options --enable-static
ac_add_options --disable-shared
ac_add_options --disable-tests
ac_add_options --disable-short-wchar
ac_add_options --enable-extensions=default,python/xpcom
</pre>
<p>The two last lines are the most important for this process.
</p><p>Now, launch the build.
</p><p>Note:  Previous versions of the PyXPCOM library are provided <a class="external" href="http://aspn.activestate.com/ASPN/Downloads/Komodo/PyXPCOM/">here</a>, although    download and use of an old version is not recommended.
</p>
<h4 name="Defining_the_interface"> Defining the interface </h4>
<p>Make a file named "py_simple.idl", to define the interface:
</p>
<pre>#include "nsISupports.idl"
[scriptable, uuid(2b324e9d-a322-44a7-bd6e-0d8c83d94883)]
interface nsIPySimple : nsISupports
{
    attribute string yourName;
    void write( );
    void change(in string aValue);
};
</pre>
<p>This is the same as the <code>nsISimple</code> interface used <a class="external" href="http://books.mozdev.org/html/mozilla-chp-8-sect-2.html">here </a>.  Theoretically, because several components can share an interface, the same file could be used.
</p><p>Pay special attention to types here - Python and JavaScript are both loosely-typed, so it's fairly easy to pass information from one to the other.  
</p><p>Note: There are exceptions; see <a class="external" href="http://aspn.activestate.com/ASPN/Mail/Message/pyxpcom/2484414">this discussion</a> for information on the use of <code>string</code> and <code>wstring</code> for unicode transfer. See <a class="external" href="http://www.mozilla.org/scriptable/xpidl/idl-authors-guide/rules.html">here</a> for info on describing interfaces, and on which types can be used.
</p>
<h5 name="Registring_the_interface"> Registring the interface </h5>
<p>In the "components" directory, execute :
</p>
<pre>../xpidl -m typelib -w -v -I /usr/share/idl/mozilla/ nsIPySimple.idl
</pre>
<p>xpidl will then create nsIPySimple.xpt, which should be placed correctly, (e.g. in the "components" directory).
</p>
<h4 name="Implementing_the_component"> Implementing the component </h4>
<p>Unlike C++, PyXPCOM does much of the work for you.
</p><p>Make a file named "py_simple.py" for the actual code (again, in the 'components': directory)
</p>
<pre class="eval">from xpcom import components, verbose

class PySimple: #PythonTestComponent
    _com_interfaces_ = components.interfaces.nsIPySimple
    _reg_clsid_ = "{c456ceb5-f142-40a8-becc-764911bc8ca5}"
    _reg_contractid_ = "@mozilla.org/PySimple;1"
    def __init__(self):
        self.yourName = "a default name" # or mName ?

    def __del__(self):
        if verbose:
            print "PySimple: __del__ method called - object is destructing"

    def write(self):
        print self.yourName

    def change(self, newName):
        self.yourName = yourName
</pre>
<p>Then register your component; the procedure is the same for any component, but will not work if Python components weren't enabled.
</p><p>To register the component, <code>touch</code> the .autoreg (a hidden file) in the bin directory, or delete xpti.dat. Then, the next time Mozilla starts, it will rebuild the index of components, including any new one in the 'components' directory.  It is helpful to then start Mozilla from the command line to see if new components register successfully.
</p>
<h4 name="Testing_it"> Testing it </h4>
<p>To see this work, you will have to start Firefox from the command line, since that'll be where the stuff will be printed out.
</p>
<h3 name="External_links"> External links </h3>
<ul><li> <a class="external" href="http://books.mozdev.org/html/mozilla-chp-8-sect-2.html">Creating XPCOM components</a>, on which this short tutorial is based.
</li><li> A three-parts tutorial on <a class="external" href="http://www-128.ibm.com/developerworks">ibm developWorks</a>:
<ul><li> <a class="external" href="http://www-128.ibm.com/developerworks/webservices/library/co-pyxp1/">Getting to know PyXPCOM</a> - info on building PyXPCOM (and maybe Mozilla) to get it to work.
</li><li> <a class="external" href="http://www-128.ibm.com/developerworks/webservices/library/co-pyxp2.html">Getting started with PyXPCOM, part 2</a> - accessing xpcom from Python.
</li><li> <a class="external" href="http://www-128.ibm.com/developerworks/webservices/library/co-pyxp3/">Getting started with PyXPCOM, part 3</a> - Creating your own compomnents. The problem with this one is that the <a class="external" href="http://www-128.ibm.com/developerworks/webservices/library/co-pyxp3/listing2.html">sample code they give</a> is slightly broken (it ends with a "retu" which shouldn't be there. I haven't tried it, but it looks like nothing is missing, so getting rid of the "retu" should make it work fine.).
</li></ul>
</li></ul>
Revert to this revision