<?xml version="1.0" encoding="iso-8859-1"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<title>Comments on article "Python plugins egg cooking mini-howto"</title>
<link>http://base-art.net/Articles/64/</link>
<description>&lt;p&gt;Eggs are being more and more used in Python land. One thing Python
developers can do easily with them is plugins cooking. They are used
in Paste*, TurboGears and Trac for instance, so i wanted to see how to
design a simple mini plugins based system.&lt;/p&gt;
&lt;p&gt;The main requirement here is &lt;a class="reference" href="http://cheeseshop.python.org/pypi/setuptools"&gt;setuptools&lt;/a&gt; (i link directly to PyPI
because Peak's wiki lags quite a bit currently). Setuptools supply a
mechanism to plug systems together called &lt;strong&gt;entry points&lt;/strong&gt;, so in your
framework you can search plugins by entrypoint, and each egg supplying
the entry point would be found.&lt;/p&gt;
&lt;p&gt;For the lazy people i made a little &lt;a class="reference" href="http://base-art.net/static/sample_plugin_system.tgz"&gt;archive&lt;/a&gt;, holding the few lines of
code showed in this article. We'll use an entry point called
&amp;quot;my.plugins&amp;quot;. Create a new tree structure which will be our first
plugin base:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
foo
|-- foo_plugin
|   |-- __init__.py
|   `-- foo.py
`-- setup.py
&lt;/pre&gt;
&lt;p&gt;In the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;setup.py&lt;/span&gt;&lt;/tt&gt;, declare the setup() and don't forget the entry points!&lt;/p&gt;
&lt;pre class="literal-block"&gt;
from setuptools import setup, find_packages

setup(
  name=&amp;quot;Foo&amp;quot;,
  version=&amp;quot;0.0&amp;quot;,
  description=&amp;quot;&amp;quot;&amp;quot;Foo plugin&amp;quot;&amp;quot;&amp;quot;,
  author=&amp;quot;Phil&amp;quot;,
  packages=['foo_plugin'],
  entry_points=&amp;quot;&amp;quot;&amp;quot;
  [my.plugins]
  myFoo = foo_plugin.foo:Foo
  &amp;quot;&amp;quot;&amp;quot;)
&lt;/pre&gt;
&lt;p&gt;Basically we have one entry point labelled &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;myFoo&lt;/span&gt;&lt;/tt&gt; in the &amp;quot;category&amp;quot;
called &amp;quot;my.plugins&amp;quot;. The entry point points to the Foo class of the
module foo_plugin.foo. That's quite simple, no ? Next step, in the
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;foo_plugin/foo.py&lt;/span&gt;&lt;/tt&gt;, declare your Foo class:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
print 'Foo loading!'

class Foo:

    def echo(self, message):
        &amp;quot;&amp;quot;&amp;quot; sample method, returning its argument &amp;quot;&amp;quot;&amp;quot;
        return message
&lt;/pre&gt;
&lt;p&gt;The next step is to package your foo plugin to a full fledged egg and
to install it using easy_install:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cd foo
$ python setup.py bdist_egg
$ sudo easy_install dist/Foo-0.0-py2.3.egg
&lt;/pre&gt;
&lt;p&gt;One alternate, and simpler way to go when you are developing your plugin:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cd foo
$ sudo python setup.py develop
&lt;/pre&gt;
&lt;p&gt;Thus, you don't need to re-compile the egg each time you modify your
code, setuptools directly access to it via a link (as i understood it,
i may be wrong here). Now the code to search and load our plugins,
create a file called &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;load_plugins.py&lt;/span&gt;&lt;/tt&gt; with following code included:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
import pkg_resources

for entrypoint in pkg_resources.iter_entry_points(&amp;quot;my.plugins&amp;quot;):
    plugin_class = entrypoint.load()
    print entrypoint.name, plugin_class
&lt;/pre&gt;
&lt;p&gt;Execute it and here we go, the foo plugin magically pops up:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ python load_plugins.py
Foo loading!
foo_plugin.foo.Foo myFoo
&lt;/pre&gt;
&lt;p&gt;After that, the developer can instantiate the class, and play with the
plugin. That's all for now, i could have used interfaces to infer the
plugin API, but i'm too lazy for now ;-) The interested user should read
the &lt;a class="reference" href="http://trac-hacks.org/wiki/EggCookingTutorial"&gt;Trac Egg Cooking tutorial&lt;/a&gt; which explains how to design trac
plugins using the trac components architecture based on interfaces. This
document is really worth looking at, Trac is a good piece of code,
really well-designed IMHO.&lt;/p&gt;
</description>
<language>en</language>
<copyright>The contents of this blog are available for non-commercial use only.</copyright>
<generator>Alinea http://pythonfr.org/alinea/</generator>


<item>
<title>phil on Python plugins egg cooking mini-howto</title>
<link>http://base-art.net/Comments/182/</link>
<guid isPermaLink="true">http://base-art.net/Comments/182/</guid>
<description><![CDATA[
&lt;p&gt;One thing about Trac's design, i've just seen some slides about Eclipse RCP and both seem to share a lot from the architecture design, like components and plugins extension points&lt;/p&gt;
&lt;p&gt;This is probably a coincidence, anyway fun to notice :-)&lt;/p&gt;

]]></description>
<dc:creator>phil</dc:creator>
<dc:date>2006-02-02T22:09:22Z</dc:date>
</item>


</channel>
</rss>
