First checkin of the Python XPCOM bindings.

git-svn-id: svn://10.0.0.236/trunk@87331 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
markh%activestate.com
2001-02-19 05:24:45 +00:00
parent 0b610ca389
commit abe83923e1
70 changed files with 13648 additions and 0 deletions

View File

@@ -0,0 +1,135 @@
<html>
<!-- Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Python XPCOM Advanced Topics</title>
</head>
<body>
<h1>Python XPCOM Advanced Topics</h1>
<p>This document contains a series of tidbits that don't fit
anywhere else. As the Python XPCOM Package documentation matures, most of
these topics will have another home.</p>
<h2>XPCOM Services</h2>
<p>An XPCOM service is simply a singleton registered by name.&nbsp; Python has
full support for both using and implementing XPCOM services.&nbsp; To use a
service, use <i>xpcom.components.services</i> just like the JavaScript
counterpart.&nbsp; There is nothing special about implementing a service in
Python; see the standard XPCOM documentation on services for more information.</p>
<h2>nsISupports Primitives.</h2>
<p>There is a set of interfaces described in <i>nsISupportsPrimitives.idl</i>, which I
term collectively the <i>nsISupports Primitives Interfaces</i>.&nbsp; These
are a set of interfaces a component can support to allow automatic conversion to
and from many basic types.&nbsp; For example, an interface can define that it
supports the <i>nsISupportsString</i> interface, and this could be used by any
program that wishes to get a string representation of the object.&nbsp; If an
interface wishes to expose itself as a &quot;boolean value&quot;, it may choose
to support the <i>nsISupportsPRBool</i> interface.</p>
<p>When you call an XPCOM object (i.e., you have an XPCOM interface you are
calling), you can use
the builtin functions <i>str()</i>, <i>int()</i>, <i>long()</i> etc., on the
object<i>.</i>&nbsp; In the
case of <i>str()</i>, if the object does not support the <i>nsISupportsString</i>
or <i>nsISupportsWString</i> interfaces, the default string <i>str()</i> for the
object will be returned (i.e., what is normally returned for most XPCOM objects -
support for these interface is not very common!).&nbsp; In the case of the numeric functions, a <i>ValueError</i>
exception will be raised if the objects do not support any interface that can be
used for the conversion.&nbsp;<i>ValueError</i> is used instead of <i>TypeError</i>,
as the type itself (i.e., an XPCOM object) can sometimes be used in this context -
hence it is the specific <i>value</i> of the object that is the problem.</p>
<p>The use of <i>repr()</i> on an XPCOM interface object prevents support
attempts for these interfaces, and allows you to see the
&quot;real&quot; object, rather than what the object wants you to see!</p>
<p>When you implement an XPCOM object, you have two choices for implementation
of these interfaces:</p>
<ul>
<li>You can explicitly handle these interfaces like any other interface.&nbsp;
In this case, you have full control.&nbsp; However, if you
implement only one of these standard interfaces, then you are only
overriding the default behavior for that specific interface - all other
interfaces not explicitly listed in your class will still get the behavior
described below.<br>
</li>
<li>If your class does not define support for these interfaces, the framework
will use standard Python class semantics to implement them - i.e., if your
class provides a <i>__str__</i> method, it will be used to implement <i>nsISupportsString</i>
and <i>nsISupportsWString</i>, if you provide <i>__int__</i>, <i>__long__</i>,
<i>__float__</i> etc., methods, they will be used to implement the numeric
interfaces.&nbsp; If your class defines no such special methods, then the <i>
QueryInterface()</i> for those interfaces fails (rather than the QI succeeding
and the operation to fetch the data failing).</li>
</ul>
<blockquote>
<p>This allows for an interesting feature that would not normally be
possible.&nbsp; Consider Python code that does a <i>str()</i> on an&nbsp; XPCOM
interface, and where the XPCOM interface itself is implemented in Python and
provides a <i>__str__</i> method.&nbsp; The <i>str()</i> on the original
interface queries for the <i>nsISupportsString</i> interface.&nbsp; The
Python implemented object responds to this interface and delegates to the <i>__str__</i>
method. At the end of all this, <i>str()</i> returns the same result
as if the objects were native Python objects with no XPCOM layer in between.</p>
</blockquote>
<h2>Enumerators</h2>
<p>The primary enumerator used by XPCOM is <i>nsISimpleEnumerator</i>.
Although the Python XPCOM package has full support for <i>nsIEnumerator</i>,
since this interface is not &quot;scriptable&quot;, you should avoided using it in interfaces
you design.</p>
<p>When you use <i>nsISimpleEnumerator</i> from Python, the following enhancements
are available:</p>
<ul>
<li>The <i>GetNext()</i> method takes an optional IID as a parameter. If
this is specified, the returned object will be of this interface.&nbsp; This
prevents the manual <i>QueryInterface()</i> generally required from other
languages.</li>
<li>There is a <i>FetchBlock(num, [iid])</i> method, which fetches the
specified number of elements in one operation and returns a Python
list. This can be useful for large enumerator sets, so the loop
iterating the elements runs at full C++ speed.</li>
</ul>
<p><i>nsIEnumerator</i> has similar enhancements.</p>
<p>When implementing a Python XPCOM object, the Python class <i>xpcom.server.enumerator.SimpleEnumerator()</i>
can be used.&nbsp; You can pass a standard Python sequence (list, etc), and it
will be correctly wrapped in an <i>nsISimpleEnumerator</i> interface.</p>
<h2>Files</h2>
<p>The Python XPCOM package provides an <i> xpcom.file</i> module.&nbsp; This implements
a Python-like file object on top of the XPCOM/Mozilla stream interfaces.&nbsp;
When run from within the Mozilla environment, this allows you to open almost any
URL supported by Mozilla (including &quot;chrome://&quot; etc.,).</p>
<p>See this module for more information, including test code.</p>
<h2>XPCOM Object Identity</h2>
<p>XPCOM has defined rules for object identity and for how objects must behave
in their <i> QueryInterface()</i> implementations.&nbsp; The Python XPCOM framework
manages this for you; your code can return new Python instances etc., when
responding to new interfaces, and the framework itself will ensure the XPCOM
semantics are followed.&nbsp; Critically, the framework provides no mechanism
for breaking these rules.</p>
<h2>Policies</h2>
<p>The Python XPCOM framework has the concept of &quot;policies&quot; that
define how XPCOM semantics are mapped to Python objects.&nbsp; It is the policy
that implements delegation of <i> QueryInterface()</i>, translates property
references into direct property references, and failing that, &quot;get_name&quot;
and &quot;set_name&quot; calls, decides how to handle exceptions in the
component, and so on.</p>
<p>The default policy is very flexible and suitable for most purposes.
Indeed, the Komodo project has never had to implement a custom policy.
However, you should be aware the feature exists should you wish to do some
bizarre things, such as using Python as a bridge between XPCOM and some other
component technology.</p>
</body>
</html>

View File

@@ -0,0 +1,84 @@
<html>
<!-- Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Architecture</title>
</head>
<body>
<h1>Python XPCOM Package Architecture</h1>
<h2><a name="Architecture">Architecture</a></h2>
<p>Much of the design for the Python XPCOM Package has been borrowed from the Python MS-COM
extensions in <i>win32com</i>. Most of the major limitations and drawbacks in the <i>win32com</i>
design have been addressed, mainly &quot;auto-wrapping&quot; of
interface objects, which is not supported by <i>win32com</i>.</p>
<p>Like <i>win32com</i>, this architecture includes the concept of <i>client COM</i> and <i>server
COM.</i> </p>
<p>Client COM:</p>
<ul>
<li>calls other interfaces</li>
<li>is supported by <i>PyInterfaces</i> implemented in C++, which assists
in making the COM calls</li>
<li>is supported by <i>PyGateways</i>, which assists in receiving
external COM calls and dispatching them to the correct Python object</li>
<li> is supported in the <i>xpcom/client</i> package</li>
</ul>
<p>Server COM:</p>
<ul>
<li>implements interfaces for use by other XPCOM applications or components</li>
<li> is
supported in the <i>xpcom/server</i> package</li>
</ul>
<p>The XPConnect framework is very powerful, and far exceeds what COM's <i>
IDispatch</i> can offer.&nbsp; Thus, we are able to get by with far fewer interfaces
supported in the C++ level, and defer most things to the Python code that uses
XPConnect.&nbsp; As a result, the requirement for a huge number of interfaces to
exist in the <i>.pyd</i> does not exist.&nbsp; There are, however, a number of
interfaces that do require native C++ support: these are interfaces
required to &quot;boot&quot; the XPConnect support (i.e., the interfaces that are
used to get information about interfaces), and also two gateways that need to
work without interface information available. This last requirement is
due to the XPCOM shutdown-ordering - it may be a bug, but is not an unreasonable
amount of code anyway.</p>
<p><b>Auto-wrapping</b> of COM objects is supported by both client COM and
server COM.&nbsp;For client COM, auto-wrapping means that the
Python programmer always sees Python &quot;component&quot; objects, rather than
raw C++ interface objects; to the user, it all appears to &quot;just
work&quot;.&nbsp; This is a major source of frustration in the <i>win32com</i>
framework.</p>
<p>For server COM, auto-wrapping means that you can
pass Python instances wherever a COM object is expected. If the Python
instance supports COM interfaces, by virtue of having a <i>_com_interfaces_</i>
attribute that lists the interface requested, it will be automatically wrapped
in the correct COM object.&nbsp;</p>
<p><b>Error Handling:</b> The C++ framework has good error handling support,
and uses the XPCOM console service to log debug messages, Python exceptions and
tracebacks.&nbsp; <i>win32com</i> does not have good exception/traceback support
at the C++ level, mainly because COM does not define a service like
the console where debug messages can go.&nbsp; This does mean that in Mozilla
release builds, these debug messages are likely to be lost, but the <i>--console</i>
command line option to a release Mozilla will get them back.&nbsp; Therefore,
the other error-support utilities, such as the error callbacks made on the
policy object, may be used.</p>
<p><b>Component Loader, Modules and Factories:</b>&nbsp; XPCOM has the concept
of a component loader - a module used to load all components of a
particular type.&nbsp; For example, the <i>moz.jsloader.1</i> component loads all
the JavaScript components.&nbsp;Similarly, the <i>moz.pyloader.1</i>
component loads all Python components.&nbsp; However, unlike
JavaScript, the Python component loader is actually implemented in Python
itself!&nbsp;Since the Python component loader can not be used to load
itself, this component has some special code, <i>pyloader.dll,</i> to boot-strap itself.</p>
<p>This means is that all XPCOM components, including the Python loader itself and all
XPCOM module and factory interfaces, are implemented in
Python.&nbsp;<b>There are no components or interfaces implemented purely in C++
in this entire package!</b></p>
</body>
</html>

View File

@@ -0,0 +1,198 @@
<html>
<!-- Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Configuring your Environment</title>
</head>
<body>
<h1>Building, Configuring and Testing Python XPCOM Package</h1>
<p>This document attempts to explain how to build, configure and test the
Python XPCOM Package. This document assumes you have already successfully
built
Mozilla from source and your environment is currently set up for such a build -
see the <a href="http://www.mozilla.org/build/">Mozilla build documentation</a>
for more information.</p>
<p>This section covers:</p>
<ul>
<li>
<p align="left"><a href="#ConfigureTheEnvironment">Configuring your
Environment</a></li>
<li>
<p align="left"><a href="#BuildingTheExtensions">Building</a></li>
<li>
<p align="left"><a href="#RunningTheTests">Testing your Setup</a></li>
<li><a href="#Registration">Registering the Loader and Test
Component</a></li>
<li><a href="#RunningTheTests">Running the test suite</a></li>
</ul>
<h2><a name="ConfigureTheEnvironment">Configuring your Environment</a></h2>
<p>In addition to the existing environment requirements for building Mozilla itself, the
Python XPCOM package has the following requirements:</p>
<ul>
<li>
<a name="MozillaDirectory"><b>Mozilla Directory</b></a><b> - </b>Ensure the Mozilla
<i> bin</i> directory is on your PATH
(LD_LIBRARY_PATH
on Unix) so Python can locate the <i> xpcom.dll</i> module needed for
core XPCOM services.</li>
<li><a name="PYTHONPATH"><b>PYTHONPATH</b></a> - <tt>PYTHONPATH</tt> needs to be set appropriately.&nbsp;Ensure
the parent to this <i>xpcom</i> directory is on your path so &quot;import
xpcom&quot; locates this directory.&nbsp; Note that the Mozilla <i>components</i> directory does not need to be on the <tt>PYTHONPATH</tt>,
but any modules used by your components must be set correctly.&nbsp; If anything
is wrong here you should get a normal <tt>ImportError</tt>.</li>
</ul>
<blockquote>
<p>Note that on Windows, the PYTHONPATH is generally maintained in the
Registry; however, you can set this variable at a DOS prompt, and it will still be
added to the core PYTHONPATH.
</blockquote>
<h2><a name="BuildingTheExtensions">Building</a></h2>
<p>The initial release of the Python XPCOM package has a very simple, hard-coded
build process.&nbsp; The intention is to include this package in the Mozilla
source tree, and integrate the build with the Mozilla build.&nbsp; Until this
happens, perform the following steps:</p>
<ul>
<li>Ensure you can successfully build Mozilla itself from source-code.</li>
<li>Unpack this source code, and change to the <i>xpcom</i> directory under
the root <i>PyXPCOM</i> directory.</li>
<li>For Windows, edit <i>makefile.stupid.win</i>, while for Linux, edit <i>makefile.stupid.linux</i></li>
<li>As per the instructions at the top of the makefile, edit the MOZ_SRC,
INSTALLDIR and PYTHON_SRC definitions appropriately.</li>
</ul>
<h3>Build Example: Building on Windows</h3>
<p>For this example, we will assume that the source-code for Mozilla is in C:\src\mozilla,
the source-code for the PyXPCOM package is in <i>c:\src\pyxpcom</i>. Further, we assume
that you have Python 2.0 installed in <i>C:\Python20</i>, and wish to install
the built Python XPCOM package so it exists in <i>C:\Python20\xpcom</i>.</p>
<p>To build the package in this environment, you would perform the following
steps:</p>
<ul>
<li>Unpack the PyXPCOM package source-code into the appropriate directory</li>
<li>Edit makefile.stupid.win with the following changes:<br>
<i>MOZ_SRC=c:\src<br>
INSTALLDIR=C:\Python20<br>
PYTHON_SRC=C:\Python20</i></li>
<li>&nbsp;From the top-level Python xpcom source directory (i.e., the
directory with <i>makefile.stupid.win</i>), execute the command:<br>
<i>nmake -f makefile.stupid.win install</i></li>
</ul>
<p>NOTE: To build a Debug version of the Python XPCOM library, you can add <i>DEBUG=1</i>
to the nmake command-line.</p>
<p>If everything appears to work and you are brave, you may also like to execute
<i>make -f makefile.stupid.win test</i> to execute the test script.&nbsp;
Otherwise, continue to the following section where we confirm the installation
step-by-step.</p>
<h3>Build Example: Building on Linux</h3>
<p>For this example, we will assume that the source-code for Mozilla is in ~/src/mozilla,
the source-code for the PyXPCOM package is in ~/src/pyxpcom. Further, we assume
that you have ActivePython 2.0 installed in <i>/usr/local/ActivePython2.0</i>,
and wish to install the built Python XPCOM package so it exists in <i>/usr/local/ActivePython2.0/lib/python2.0/site-packages/xpcom</i>.</p>
<p>To build the package in this environment, you would perform the following
steps:</p>
<ul>
<li>Unpack the PyXPCOM package source-code into the appropriate directory</li>
<li>Edit makefile.stupid.linux with the following changes (substituting
username accordingly):<br>
<i>MOZ_SRC=/home/username/src<br>
INSTALLDIR=/usr/local/ActivePython-2.0/site-packages<br>
PYTHON_SRC=/usr/local/ActivePython-2.0</i></li>
<li>Build: As a regular user, from the top-level Python xpcom source
directory (i.e., the directory with <i>makefile.stupid.linux</i>), execute
the command:<br>
<i>make -f makefile.stupid.linux DEBUG=1</i></li>
<li>Install: Log in as a user with permissions to install into the relevant directories
(usually the root user).&nbsp; From the top-level Python xpcom source
directory (i.e., the directory with <i>makefile.stupid.linux</i>), execute
the command:<br>
<i>make -f makefile.stupid.linux DEBUG=1 install</i></li>
<li>Switch back to a regular user, ready for testing!</li>
</ul>
<p>NOTE: The instructions above are for a Debug build, as this is the default
Mozilla build type.&nbsp; If you have configured Mozilla to build a Release
version of Mozilla, you can drop the DEBUG=1 option.&nbsp; It is important that
PyXPCOM and Mozilla itself are consistent with respect to Release and Debug
builds.&nbsp; For more details, please consult the makefile.</p>
<p>If everything appears to work and you are brave, you may also like to execute
<i>make -f makefile.stupid.linux test</i> to execute the test script.&nbsp;
Otherwise, continue to the following section where we confirm the installation
step--by-step.</p>
<h2><a name="RunningTheTests">Testing your Setup</a></h2>
<p>The Python XPCOM Package has a complete test suite.&nbsp; If you are
impatient, you can simply execute <i>make -f makefile.stupid.linux test</i> (for
Linux) or <i>nmake -f makefile.stupid.linux test</i> (for Windows).&nbsp; If
this command indicates that the tests succeeded, then you can ignore the rest of
this section.</p>
<p>In the rest of this section, we walk through some simpler tests a step at a time,
to help diagnose any problems.</p>
<p><b>Note:</b> We recommend you do all your testing outside of <i> mozilla.exe</i>; it is far simpler to test all of
this using the PyXPCOM package stand-alone.</p>
<p><b>Note:</b> On Windows, if you use a debug build of Mozilla (i.e., in <i>dist\WIN32_D.OBJ\bin)</i>,
you <b>must</b> use <i>python_d.exe</i>; if you use a release build (i.e., in
a <i>dist\WIN32_O.OBJ\bin</i> directory), you must use <i>python.exe</i>.&nbsp;
<i>makefile.stupid.win</i> handles this automatically.</p>
<p>To test your setup:</p>
<ol>
<li>Start Python, and check<br>
&gt;&gt;&gt; <i>import xpcom</i><br>
works. If not, <a href="#PYTHONPATH">check your PYTHONPATH</a> - the
main PyXPCOM package can not be located..</li>
<li>Check<i><br>
&gt;&gt;&gt; import xpcom._xpcom</i><br>
works. If not, then most likely your <a href="#MozillaDirectory">Mozilla
directory is not on your path</a>, or something is wrong with <i>_xpcom(_d).pyd/_xpcommodule.so</i>.</li>
<li>Next run a simple test: <i>test/test_misc.py</i>.&nbsp;With a Windows debug build, the command may look like:<br>
<i>C:\Anywhere&gt; python_d \src\python\xpcom\test\test_misc.py<br>
</i>or on Linux<br>
<i>/home/user/src/mozilla/dist/bin$ python /home/user/src/python/xpcom/test/test_misc.py</i></li>
</ol>
<p>If you can't get this going, you won't get much further! If you do, the
next step is to register our test component and run our full test suite.</p>
<h2><a name="Registration">Registering the Loader and Test Component</a></h2>
<p>First register the generic Python loader. For instructions, see the <a href="file:///F:/src/as/Komodo/src/pyxpcom/xpcom/doc/architecture.html">architecture
document</a>.&nbsp;Do this only once, regardless of how many
Python components you have.&nbsp; Then install the test component itself, and
finally you can test it!</p>
<h3>Registering the Python Loader and Component</h3>
<p>To register the Python Loader and Component:</p>
<ol>
<li>Ensure the build process has put <i>pyloader.dll </i>(or <i>modpyloader.so</i>
for Unix), and the files <i> py_test_component.py </i> and <i> py_test_component.idl</i> into
the Mozilla <i>bin/components</i> directory.&nbsp; If not, copy the files
there manually.</li>
<li>Run <i>regxpcom</i>.&nbsp;<i>regxpcom</i> is a standard Mozilla
executable, found in the <i>bin</i> directory, that detects whether the DLL and .py
files have been added and registers them accordingly.&nbsp; You should
see a few messages that include the following:</li>
</ol>
<blockquote>
<pre>Registering: PythonComponentLoader
Registered 1 Python components in pyloader.dll
nsNativeComponentLoader: autoregistering succeeded
Auto-registering all Python components in F:\src\mozilla\dist\WIN32_D.OBJ\bin\components
Registering: PythonTestComponent
Registered 1 Python components in py_test_component.py</pre>
</blockquote>
<p>If so (or you see no message at all), you are ready to run the test suite.</p>
<p><b>Note</b>: If you execute this same step a second time, you will not
see any of the above mentioned messages.&nbsp;XPCOM knows that nothing has
changed since you last ran <i>regxpcom</i>, so nothing is registered.&nbsp; If
you do not see these messages the first time you run it, there is the
possibility that some other process, possibly the build process, has already
executed this step.</p>
<h2><b>Running the Test Suite</b></h2>
<p>To run the test suite, run <i>xpcom/test/regrtest.py.</i>&nbsp; This runs the
tests and ensures that the test output is as expected.&nbsp; If all tests
pass, you have a fully functioning Python XPCOM package.&nbsp; Enjoy!</p>
</body>
</html>

View File

@@ -0,0 +1,54 @@
<html>
<!-- Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. -->
<head>
<meta http-equiv="Content-Language" content="en-au">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Credits and Acknowledgements</title>
</head>
<body>
<h1>Credits and Acknowledgements</h1>
<h2>ActiveState Tool Corporation</h2>
<p>The Python XPCOM Package was developed primarily by <a href="mailto:markh@activestate.com">Mark
Hammond</a> of <a href="http://www.ActiveState.com">ActiveState Tool Corporation</a>.</p>
<p>The developers on the <a href="http://www.ActiveState.com/Products/Komodo">Komodo
project</a> deserve high praise for putting up with early versions when almost
nothing worked, and for believing in Python as a viable XPCOM language.&nbsp;
Their feedback and patience has allowed the first public release to be amazingly
functional and bug-free.</p>
<h3>Komodo Development Team (at December 2000)</h3>
<p><a href="mailto:davida@activestate.com">David Ascher</a>, <a href="mailto:aaronb@ActiveState.com">Aaron Bingham</a>,
<a href="mailto:bindu@activestate.com">Bin Du</a>, <a href="mailto:markh@activestate.com">Mark
Hammond</a>, <a href="mailto:trentm@activestate.com">Trent Mick (build god)</a>,&nbsp;
<a href="mailto:paulp@activestate.com">Paul Prescod</a>,&nbsp; <a href="mailto:ericp@ActiveState.com">Eric Promislow</a>,
<a href="mailto:kens@ActiveState.com">Ken Simpson</a>, <a href="mailto:neilw@ActiveState.com">Neil Watkiss</a>,
<a href="mailto:AudreyS@ActiveState.com">Audrey Schumacher</a>.</p>
<h2>Mozilla/Netscape</h2>
<p>The following people at <a href="http://www.netscape.com">Netscape</a> and <a href="http://www.mozilla.org">Mozilla</a>
(or not there but still heavily involved in the project) have provided enormous
help in getting things integrated with their build system, answering us on the
newsgroup, teaching us the finer points of XPCOM, gently slapping us for accidentally
referring to <i>jscript</i>, etc., and otherwise lending us a clue in the
Mozilla/Netscape/XPCOM world.</p>
<p><a href="mailto:jband@netscape.com">John Bandhauer</a>, <a href="mailto:brendan@meer.net">Brendan
Eich</a>, <a href="mailto:shaver@zeroknowledge.com">Mike Shaver</a>, <a href="mailto:evaughan@netscape.com">Eric Vaughan</a>,
<a href="mailto:hyatt@netscape.com">David Hyatt</a></p>
<h2>External Contributors</h2>
<p>The following people have made contributions to the project, simply because
they find it useful and enjoy supporting Open Source projects.</p>
<p><a href="mailto:cmeerw@web.de">Christof Meerwald</a></p>
<h2>Documentation Credits</h2>
<p>The following people have contributed to the Python XPCOM Package
documentation&nbsp;</p>
<p><a href="mailto:markh@activestate.com">Mark
Hammond</a>, <a href="mailto:AudreyS@ActiveState.com">Audrey Schumacher</a></p>
</body>
</html>

View File

@@ -0,0 +1,240 @@
<html>
<!-- Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Python XPCOM Package Tutorial</title>
</head>
<body>
<h1>Python XPCOM Package Tutorial</h1>
<p>This is a quick introduction to the Python XPCOM Package. We assume that you have a good understanding of Python and <a href="http://www.mozilla.org/projects/xpcom/">XPCOM</a>,
and have experience both using and implementing XPCOM objects in some other
language (e.g., C++ or JavaScript). We <b><i>do not</i></b> attempt to
provide a tutorial to XPCOM or Python itself, only to using Python <i>and</i>
XPCOM.</p>
<p>This tutorial contains the following sections:</p>
<ul>
<li><a href="#Using">Using XPCOM Objects and Interfaces</a> - when you wish to
<i>use</i> a component written by anyone else in any XPCOM supported
language.</li>
<li><a href="#Implementing">Implementing XPCOM Objects and Interfaces</a> -
when you wish to implement a component for use by anyone else in any xpcom
supported language.</li>
<li><a href="#Parameters">Parameters and Types</a> - useful information
regarding how Python translates XPCOM types, and handles byref parameters.</li>
</ul>
<p>For anything not covered here, try the <a href="advanced.html">advanced
documentation</a>, and if that fails, use the source, Luke!</p>
<h2><a name="Using">Using XPCOM object and interfaces.</a></h2>
<p>The techniques for using XPCOM in Python have been borrowed from JavaScript -
thus, the model described here should be quite familiar to existing JavaScript
XPCOM programmers.</p>
<h3>xpcom.components module</h3>
<p>When using an XPCOM object, the primary module used is the <u><i>xpcom.components</i></u>
module.&nbsp; Using this module, you can get a Python object that supports any
scriptable XPCOM interface. Once you have this Python object, you can
simply call XPCOM methods on the object, as normal.</p>
<p>The <u><i>xpcom.components</i></u> module defines the following public
members:</p>
<table border="1" width="100%">
<tr>
<td width="16%"><b>Name</b></td>
<td width="84%"><b>Description</b></td>
</tr>
<tr>
<td width="16%">classes</td>
<td width="84%">A mapping (dictionary-like object) used to get XPCOM
&quot;classes&quot;.&nbsp; These are indexed by XPCOM contract ID, just
like the JavaScript object of the same name.&nbsp;&nbsp;
<p>Example:</p>
<pre>cls = components.classes[&quot;@mozilla.org/sample;1&quot;]
ob = cls.createInstance() # Now have an nsISupports</pre>
</td>
</tr>
<tr>
<td width="16%">interfaces</td>
<td width="84%">An object that exposes all XPCOM interface IDs (IIDs).&nbsp;
Like the JavaScript object of the same name, this object uses
&quot;dot&quot; notation, as demonstrated below.
<p>Example:</p>
<pre>ob = cls.createInstance(components.interfaces.nsISample)
# Now have an nsISample</pre>
</td>
</tr>
</table>
<p>For many people, this is all you need to know. Consider the Mozilla Sample Component.&nbsp; The Mozilla Sample
Component has a contract ID of <i>@mozilla.org/sample;1</i>,
and implements the <i>nsISample</i> interface.</p>
<p>Thus, a complete Python program that uses this component is shown below.</p>
<pre>from xpcom import components
cls = components.classes[&quot;@mozilla.org/sample;1&quot;]
ob = cls.createInstance(components.interfaces.nsISample)
# nsISample defines a &quot;value&quot; property - let's use it!
ob.value = &quot;new value&quot;
if ob.value != &quot;new value&quot;:
print &quot;Eeek - what happened?&quot;</pre>
<p>And that is it - a complete Python program that uses XPCOM.</p>
<h2><a name="Implementing">Implementing XPCOM Objects and Interfaces.</a></h2>
<p>Implementing XPCOM objects is almost as simple as using them. The
basic strategy is this:</p>
<ol>
<li>Create a standard Python source file, with a standard Python class.</li>
<li>Add some special <a href="#Attributes"> attributes</a> to your class for use by the Python XPCOM
framework. This controls the XPCOM behavior of your object.</li>
<li>Implement the XPCOM <a href="#Properties"> properties</a> and methods of your classes as normal.</li>
<li>Put the Python source file in the Mozilla <i> components</i> directory.</li>
<li>Run <i> regxpcom.</i></li>
</ol>
<p>Your component is now ready to be used.</p>
<h3><a name="Attributes">Attributes</a></h3>
<p>There are two classes of attributes: those used at runtime to define the object
behavior and those used at registration time to control object
registration.&nbsp; Not all objects require registration, thus not all
Python XPCOM objects will have registration-related attributes.</p>
<table border="1" width="100%">
<tr>
<td width="17%"><b>Attribute</b></td>
<td width="83%"><b>Description</b></td>
</tr>
<tr>
<td width="17%">_com_interfaces_</td>
<td width="83%">The interface IDs (IIDs) supported by the component.&nbsp;
For simplicity, this may be either a single IID, or a list of IIDs.&nbsp;
There is no need to specify base interfaces, as all parent interfaces are
automatically supported. Thus, it is never necessary to nominate <i>
nsISupports</i> in the list of interfaces.
<p>This attribute is required. Objects without such an attribute are
deemed unsuitable for use as a XPCOM object.</td>
</tr>
<tr>
<td width="17%">_reg_contractid_</td>
<td width="83%">The contract ID of the component.&nbsp; Required if the
component requires registration (i.e., exists in the components directory).</td>
</tr>
<tr>
<td width="17%">_reg_clsid_</td>
<td width="83%">The Class ID (CLSID) of the component, as a string in the
standard &quot;{XXX-XXX-XXX-XXX}&quot; format. Required if the
component requires registration (i.e., exists in the components directory).</td>
</tr>
<tr>
<td width="17%">_reg_registrar_</td>
<td width="83%">Nominates a function that is called at registration
time. The default is for no extra function to be called. This can
be useful if a component has special registration requirements and needs
to hook into the registration process.</td>
</tr>
<tr>
<td width="17%">_reg_desc_</td>
<td width="83%">The description of the XPCOM object. This may be used by
browsers or other such objects.&nbsp; If not specified, the contract ID
is used.</td>
</tr>
</table>
<h3><a name="Properties">Properties</a></h3>
<p>A Python class can support XPCOM properties in one of two ways.&nbsp; Either
a standard Python property of the same name can exist - our sample
component demonstrates this with the <i>boolean_value</i> property.&nbsp;
Alternatively, the class can provide the <i>get_propertyName(self)</i> and <i>set_propertyName(self,
value)</i> functions (with <i>propertyName</i> changed to the appropriate value for the
property), and these functions will be called instead.</p>
<h4>Example:&nbsp; The Python XPCOM Test Component</h4>
<p>As an example, examine the Python XPCOM Test Component.&nbsp; This
code can be found in <i>py_test_component.py</i>.</p>
<pre>from xpcom import components
class PythonTestComponent:
_com_interfaces_ = components.interfaces.nsIPythonTestInterface
_reg_clsid_ = &quot;{7EE4BDC6-CB53-42c1-A9E4-616B8E012ABA}&quot;
_reg_contractid_ = &quot;Python.TestComponent&quot;
def __init__(self):
self.boolean_value = 1
...
def do_boolean(self, p1, p2):
ret = p1 ^ p2
return ret, not ret, ret
...</pre>
<p><b>Note:</b> This component only specifies the mandatory attributes - <i>_com_interfaces</i>,
<i>_reg_clsid_</i> and <i>_reg_contractid_</i>.</p>
<p>This sample code demonstrates supporting the <i>boolean_value</i> attribute,
supported implicitly, as it is defined in the IDL and exists as a real Python
attribute of that name, and a method called <i>do_boolean</i>.</p>
<h4>Tip: The xpcom/xpt.py Script</h4>
<p> The xpcom/xpt.py script is a useful script that can generate the skeleton of a class for
any XPCOM interface.&nbsp; Just specify the interface name on the command-line,
and paste the output into your source file.</p>
<p>This is the output of running this program over the <i>nsISample</i>
interface (i.e., assuming we wanted to implement a component that supported this
interface):</p>
<pre>class nsISample:
_com_interfaces_ = xpcom.components.interfaces.nsISample
# If this object needs to be registered, the following 2 are also needed.
# _reg_clsid_ = {a new clsid generated for this object}
# _reg_contractid_ = &quot;The.Object.Name&quot;
def get_value( self ):
# Result: string
pass
def set_value( self, param0 ):
# Result: void - None
# In: param0: string
pass
def writeValue( self, param0 ):
# Result: void - None
# In: param0: string
pass
def poke( self, param0 ):
# Result: void - None
# In: param0: string
pass</pre>
<p><b>Note:</b> The types of the parameters and the function itself are included in
the comments.&nbsp;You need to implement the functions
themselves.&nbsp; Another advantage of this script is that the <a href="#HiddenParams">hidden
parameters</a> are handled for you; the comments indicate when parameters
have been hidden.</p>
<h2><a name="Parameters">Parameters and Types</a></h2>
<p>This section briefly describes the XPCOM type support in
Python.</p>
<p>All XPCOM interfaces define parameters of a specific type.&nbsp; There is
currently no concept of a variant, or union of all types. Thus, the
conversion rules are very straightforward, and generally surprise free: for
any given XPCOM method, there is only one possible type for a given parameter.</p>
<h3>Type Conversion Rules:</h3>
<ul>
<li>All numeric types will attempt to be coerced to the correct type.&nbsp;
Thus, you can pass a Python float to an XPCOM method expecting an integer,
or vice-versa. Specifically, when an integer is required, you can pass
any Python object for which <i>int()</i> would succeed; for a Python float,
any object for which <i>float()</i> would succeed is acceptable.&nbsp; This
means that you can pass a Python string object as an integer, as long as the
string was holding a valid integer.</li>
<li>Strings and Unicode objects are interchangeable, but no other automatic
string conversions are performed.&nbsp; Thus, you can not pass an integer
where a string is expected, even though the reverse is true.</li>
<li>Any sequence object can be passed as an array.&nbsp; List objects are
always returned for arrays.</li>
<li>Any Python instance suitable for use as a XPCOM object (i.e., with the
<a href="#Implementing">necessary annotations</a>) can be
passed as a XPCOM object. No special wrapping step is needed to turn a
Python instance into a XPCOM object.&nbsp; Note you must pass a class <i>instance</i>,
not the class itself.</li>
<li><a name="HiddenParams">Many XPCOM <b> method signatures</b> specify
&quot;count&quot; or &quot;size&quot; parameters.&nbsp; For example, every
time an array is passed via XPCOM, the method signature will always specify
an integer that holds the count of the array.&nbsp; These parameters are
always hidden in Python.&nbsp; As the size param can be implied from the
length of the Python sequence passed, the Python programmer need never pass
these parameters;&nbsp;in contrast, JavaScript requires these redundant parameters.</a></li>
</ul>
</body>
</html>