PyXPCOM: Difference between revisions

From MozillaZine Knowledge Base
Jump to navigationJump to search
(→‎External links: (getting rid of the "retu" should work))
Line 114: Line 114:
** [http://www-128.ibm.com/developerworks/webservices/library/co-pyxp1/ Getting to know PyXPCOM] - info on building PyXPCOM (and maybe Mozilla) to get it to work.
** [http://www-128.ibm.com/developerworks/webservices/library/co-pyxp1/ Getting to know PyXPCOM] - info on building PyXPCOM (and maybe Mozilla) to get it to work.
** [http://www-128.ibm.com/developerworks/webservices/library/co-pyxp2.html Getting started with PyXPCOM, part 2] - accessing xpcom from Python.
** [http://www-128.ibm.com/developerworks/webservices/library/co-pyxp2.html Getting started with PyXPCOM, part 2] - accessing xpcom from Python.
** [http://www-128.ibm.com/developerworks/webservices/library/co-pyxp3/ Getting started with PyXPCOM, part 3] - Creating your own compomnents. The problem with this one is that the [http://www-128.ibm.com/developerworks/webservices/library/co-pyxp3/listing2.html sample code they give] is broken, for some mysterious reason. Not very good for learning how to use PyXPCOM, then.
** [http://www-128.ibm.com/developerworks/webservices/library/co-pyxp3/ Getting started with PyXPCOM, part 3] - Creating your own compomnents. The problem with this one is that the [http://www-128.ibm.com/developerworks/webservices/library/co-pyxp3/listing2.html sample code they give] 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.).


[[Category:Development]]
[[Category:Development]]
[[Category:Example code]]
[[Category:Example code]]

Revision as of 03:26, 16 November 2005

PyXPCOM is a component that allows bindings between Python and XPCOM, making it possible to write XPCOM components in Python (instead of Javascript or C++).

Here we will present an example of how to develop a simple component.

Making a simple Python XPCOM component

Python is powerful and easy; while someday we may be able to directly attach python code to our XUL, in the meantime we can already use it to make XPCOM components. The procedure still isn't seamless, but it's definitely possible. There are already some PyXPCOM tutorials on the net (see the links section at the bottom), this one is a) simple and b) works on the latest version of Firefox.

"Crreating Applications with Mozilla" already provides a tutorial for making a simple javascript or C++ component (with the nsISimple interface), here is how to make the same component in Python.

(Note that some details may be missing)

Preparation

The PyXPCOM library is, normally, already provided with mozilla. You do not want to dowload it from here - that is an old version, and won't work as well (I remember I had some problems with it, though I don't remember which ones). All you need to do is tell python where he can find the PyXPCOIM library. This is probably best done by adding a "mozillalibs.pth" (any name goes) to your python site packages directory (mine is at "/usr/lib/python2.3/site-packages"), whith only one line, the location of the packages you may want to import (the "/dist/bin/python" of your mozilla source).

Then you can do

import xpcom

in any python module (mostly, you'll do it in your component).

You will also need your mozilla to handle python. This may require special compilation (at least, it did so for me, I recompiled the whole damn thing, it takes hours). Apparently it's possible to build the PyXPCOM stuff seperately, I haven't tried. I did this with Deer Park 1.5 Beta 2 (recommended for extension development), it should be possible with older versions, but details might vary (That shouldn't matter much, since I haven't recorded all the details here).

Anyway, to build mozilla, you should get and compile the source, with the right options in the .mozconfig file (in the root of your mozilla source). I used the following:

. $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 us)

Then, launch the build !

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 we could use the same file, as we can have several components sharing an interface)

You should pay special attention to types here - Python and JavaScript are both loosely-typed, so it's fairly easy to expect to be able to pass anything from one to the other. I got bit by that one, sending a unicode string from javascript and expecting to receive a unicode string in Python, whereas only a "string" was defined in the interface file (use a wstring if you want unicode. See this discussion for a bit of info on unicode and javascript).

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 has to be in the right place, for example in the "components" directory).

Implementing the component

This is way simpler than with C++ ! PyXPCOM does a lot 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

That's all ! Then, you have to register your component; the procedure is the same as for any component, but this won't work if python components weren't enabled.

To register the component, touch the .autoreg in the bin directory (it's a hidden file). This can also be done by deleting xpti.dat. Then, next time mozilla starts, it will rebuild the index of components, including any new one in the 'components' directory (Thus, it's better to 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