<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Parijat's Weblog &#187; packaging</title>
	<atom:link href="http://parijatmishra.wordpress.com/tag/packaging/feed/" rel="self" type="application/rss+xml" />
	<link>http://parijatmishra.wordpress.com</link>
	<description>of cabbages and kings</description>
	<lastBuildDate>Mon, 05 Oct 2009 15:30:39 +0000</lastBuildDate>
	<generator>http://wordpress.com/</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<cloud domain='parijatmishra.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://www.gravatar.com/blavatar/17a05d0ba73a8bc2484cd40d87e29e98?s=96&#038;d=http://s.wordpress.com/i/buttonw-com.png</url>
		<title>Parijat's Weblog &#187; packaging</title>
		<link>http://parijatmishra.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://parijatmishra.wordpress.com/osd.xml" title="Parijat&#8217;s Weblog" />
		<item>
		<title>Python packaging: setuptools and eggs</title>
		<link>http://parijatmishra.wordpress.com/2008/10/08/python-packaging-setuptools-and-eggs/</link>
		<comments>http://parijatmishra.wordpress.com/2008/10/08/python-packaging-setuptools-and-eggs/#comments</comments>
		<pubDate>Wed, 08 Oct 2008 11:02:10 +0000</pubDate>
		<dc:creator>parijatmishra</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[boost.python]]></category>
		<category><![CDATA[easy_install]]></category>
		<category><![CDATA[eggs]]></category>
		<category><![CDATA[packaging]]></category>
		<category><![CDATA[pyrex]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[setuptools]]></category>

		<guid isPermaLink="false">http://parijatmishra.wordpress.com/?p=141</guid>
		<description><![CDATA[Developing Packages
This document describes how to create a buildable, distributable package out of
python source code.We&#8217;ll look at the popular &#8216;egg&#8217; distribution format.
Tools we need:

Python &#62;= 2.4
Setuptools

Also, highly recommended is: virtualenv
What is an egg?

Eggs are basically directories that are added to Python&#8217;s path.
The directories may be zipped.
Eggs have some meta-data

Dependencies
Entry-points


May be distributed as source
Can be discovered [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=parijatmishra.wordpress.com&blog=3282491&post=141&subd=parijatmishra&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><h2>Developing Packages</h2>
<p>This document describes how to create a buildable, distributable package out of<br />
python source code.We&#8217;ll look at the popular &#8216;egg&#8217; distribution format.</p>
<p>Tools we need:</p>
<ul>
<li>Python &gt;= 2.4</li>
<li><a class="ext-link" href="http://peak.telecommunity.com/DevCenter/setuptools"><span class="icon">Setuptools</span></a></li>
</ul>
<p>Also, highly recommended is: <a class="ext-link" href="http://pypi.python.org/pypi/virtualenv"><span class="icon">virtualenv</span></a></p>
<h2>What is an egg?</h2>
<ul>
<li>Eggs are basically directories that are added to Python&#8217;s path.</li>
<li>The directories may be zipped.</li>
<li>Eggs have some meta-data
<ul>
<li>Dependencies</li>
<li>Entry-points</li>
</ul>
</li>
<li>May be distributed as source</li>
<li>Can be discovered from PyPI</li>
</ul>
<h2>What is <tt>easy_install</tt>?</h2>
<p>A tool to find, download, compile (if needed), and install python packages. It<br />
can install eggs, or even source tarballs, as long as the tarball uses the<br />
standard python setup.py method of building itself.</p>
<h2>Egg Terminology</h2>
<ul>
<li>Distribution
<ul>
<li>a term used by Python distutils;</li>
<li>anything which can be &#8216;distributed&#8217;, really;</li>
<li>most common: tarballs, eggs.</li>
</ul>
</li>
<li>Source distribution:
<ul>
<li>A distribution that contains only source files</li>
</ul>
</li>
<li>Binary distribution:
<ul>
<li>A distribution that contains compiled &#8216;.pyc&#8217; files and C extensions</li>
<li>E.g., RPMs and eggs</li>
</ul>
</li>
<li>Egg:
<ul>
<li>A kind of binary distribution</li>
</ul>
</li>
<li>Platform dependent eggs:
<ul>
<li>Eggs which contain built C extension modules and are thus tied to an OS</li>
</ul>
</li>
<li>&#8216;develop eggs&#8217; and &#8216;develop egg links&#8217;:
<ul>
<li>develop egg links are special files that allow a source directory to be<br />
treated as if it were an installed egg.  (That is, an egg that you are<br />
&#8216;developing&#8217;!)</li>
</ul>
</li>
<li>Index server and link servers:
<ul>
<li>easy_install will automatically download distributions from the<br />
Internet. When looking for distributions, it will look at zero or more<br />
links servers for links to distributions.  They will also look on a single<br />
index server, typically (always) <a class="ext-link" href="http://www.python.org/pypi"><span class="icon">http://www.python.org/pypi</span></a>. Index servers<br />
are required to provide a specific web interface.</li>
</ul>
</li>
</ul>
<h2>Example Project</h2>
<p>Our sample project consists of this code:</p>
<ul>
<li>package &#8217;speaker&#8217;
<ul>
<li>module dog:
<ul>
<li>class Dog</li>
<li>function DogMain</li>
</ul>
</li>
<li>module gendibal
<ul>
<li>class Gendibal</li>
<li>function GendibalMain</li>
</ul>
</li>
<li>module bjarne
<ul>
<li>class Bjarne</li>
<li>function BjarneMain</li>
</ul>
</li>
</ul>
</li>
<li>pacakge &#8216;tests&#8217;
<ul>
<li>module dog_test
<ul>
<li>class DogTest</li>
</ul>
</li>
<li>module gendibal_test
<ul>
<li>class GendibalTest</li>
</ul>
</li>
<li>module bjarne_test
<ul>
<li>class BjarneTest</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>The classes Dog, Gendibal, and Bjarne are &#8220;<tt>speakers"</tt>: they all have the<br />
method <tt>greeting</tt>() which takes no arguments and returns a string containing<br />
something they said.  The Dog speaker will, of course, say &#8220;Bow, wow!&#8221;.<br />
Gendibal is a mathemetician and therefore uses prime numbers in his<br />
greetings.  Bjarne likes to talk about C++.</p>
<p>For every module and class, there is a corresponding test module and class.</p>
<p>We shall also have three scripts (i.e., programs that live in a <tt>bin</tt><br />
directory somewhere) that are intended to be launched from the command<br />
line.  The programs will be:</p>
<ul>
<li><tt>rundog</tt>: runs <tt>speaker.dog:Dogmain</tt></li>
<li><tt>rungendibal</tt>: runs <tt>speaker.gendibal:GendibalMain</tt></li>
<li><tt>runbjarne</tt>: runs <tt>speaker.bjarne:BjarneMain</tt></li>
</ul>
<h2>Directory Structure</h2>
<p>This is the intended directory structure.</p>
<pre class="wiki">Speaker/
|-- README.txt
|-- setup.cfg
|-- setup.py
|-- speaker
|   |-- __init__.py
|   |-- bjarne.cpp
|   |-- dog.py
|   `-- gendibal.pyx
`-- tests
    |-- __init__.py
    |-- bjarne_test.py
    |-- dog_test.py
    `-- gendibal_test.py</pre>
<ul>
<li><tt>Speaker</tt> is the name of the project, and it will also be the name of our<br />
package (Speaker-0.1.tgz, for e.g.);</li>
<li>Our project contains a package named <tt>speaker</tt>, where we will put our<br />
classes; we can add more packages inside later;</li>
<li><tt>setup.py</tt> and <tt>setup.cfg</tt> contain information to build our egg.</li>
<li>The <tt>tests</tt> package will contains test code.</li>
</ul>
<h2>Version 0.0: setting up the package</h2>
<p>Let&#8217;s create some dirs and files:</p>
<pre class="wiki">Speaker/
|-- setup.cfg
|-- setup.py
|-- speaker
|   |-- __init__.py
`-- tests
    |-- __init__.py</pre>
<p>Where:</p>
<ul>
<li>setup.py
<pre class="wiki">from setuptools import setup, find_packages
setup(name='Speaker',
      packages=find_packages(),
      )</pre>
</li>
</ul>
<p>The <tt>find_packages</tt> function automatically will discover your python packages<br />
and modules, and pack them up.</p>
<ul>
<li>setup.cfg
<pre class="wiki">[egg_info]
tag_build = dev</pre>
</li>
</ul>
<p>The <tt>tag_build</tt> option appends a tag of our choice to the generated<br />
filename.  We&#8217;ll see it in action in a second.</p>
<ul>
<li><tt>speaker/__init__.py</tt> and <tt>tests/__init__.py</tt> are empty files.</li>
</ul>
<p>Now we can build our package:</p>
<pre class="wiki">$ cd Speaker
$ python setup.py build
$ python setup.py bdist_egg
$ ls dist/
Speaker-0.0dev-py2.5.egg  Speaker-0.0dev.tar.gz</pre>
<p>We have just created a source distribution and a platform-independent egg, even<br />
though we don&#8217;t have a single line of useful code yet.</p>
<blockquote><p><strong>Note:</strong> the &#8216;dev&#8217; in the filename: we&#8217;ve told setuptools that our package<br />
is a in-development package and specified the tag &#8216;dev&#8217; in <tt>setup.cfg</tt>.  This<br />
actually matters when easy_install is figuring out which out of several<br />
versions of a pacakge it should download and install.  More on it later.</p></blockquote>
<h2>Version 0.1: making a releasable package</h2>
<p>Let&#8217;s update our <tt>setup.py</tt>:</p>
<div class="code">
<pre><em><span class="code-comment"># setup.py
</span></em><strong><span class="code-lang">from</span></strong> setuptools <strong><span class="code-lang">import</span></strong> setup, find_packages
<strong><span class="code-lang">import</span></strong> sys, os

version = <span class="code-string"><strong>'0.1'</strong></span><strong></strong>

setup(name=<span class="code-string"><strong>'Speaker'</strong></span><strong></strong>,
      version=version,
      description=<span class="code-string"><strong>"Demo Pakcage"</strong></span><strong></strong>,
      packages=find_packages(exclude=[<span class="code-string"><strong>'ez_setup'</strong></span><strong></strong>, <span class="code-string"><strong>'examples'</strong></span><strong></strong>, <span class="code-string"><strong>'tests'</strong></span><strong></strong>]),
      include_package_data=True,
      zip_safe=False,
      )</pre>
</div>
<p>Notes:</p>
<ul>
<li>Look at <tt>find_packages</tt> directive: some packages and modules are not going<br />
to be part of your distribution, because we want the <tt>tests</tt> and <tt>examples</tt> package, and the <tt>ez_setup.py</tt> module, to be available only to people checking out the code, not when they are downloading a built egg. (We haven&#8217;t written any exampels yet, but you were going to do it, right? ;-))</li>
<li><tt>zip_safe</tt> means that the package won&#8217;t be unzipped: stuff will run right<br />
out of the zipped directory!  Normally not useful.</li>
<li>We always want to set <tt>include_package_data</tt> to True.</li>
</ul>
<h3>Our first bit of code</h3>
<p>We create our first speaker:</p>
<div class="code">
<pre><em><span class="code-comment"># speaker/dog.py
</span></em><strong><span class="code-lang">class</span></strong> Dog(object):
    <strong><span class="code-lang">def</span></strong> <strong><span class="code-func">greeting</span></strong>(self):
        <strong><span class="code-lang">return</span></strong> <span class="code-string"><strong>"Bow, wow!"</strong></span><strong></strong></pre>
</div>
<p>and write a test:</p>
<div class="code">
<pre><em><span class="code-comment"># tests/dog_test.py

</span></em><strong><span class="code-lang">import</span></strong> unittest
<strong><span class="code-lang">from</span></strong> speaker <strong><span class="code-lang">import</span></strong> dog

<strong><span class="code-lang">class</span></strong> DogTest(unittest.TestCase):
    <strong><span class="code-lang">def</span></strong> <strong><span class="code-func">test_greeting</span></strong>(self):
        d = dog.Dog()
        self.assert_(d.greeting() == <span class="code-string"><strong>"Bow, wow!"</strong></span><strong></strong>)

<strong><span class="code-lang">if</span></strong> __name__ == <span class="code-string"><strong>"__main__"</strong></span><strong></strong>:
    unittest.main()</pre>
</div>
<p>Oops! Python does not know where to find our packages yet. So we &#8216;install&#8217; our<br />
egg as a &#8216;develop egg&#8217;:</p>
<pre class="wiki">$ python setup.py develop</pre>
<p>This will create the necessary symbolic links for python to find<br />
our packages.  Now our code will behave just as if it was<br />
installed, while letting us keep coding away.</p>
<pre class="wiki">$ python tests/dog_test.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK</pre>
<h3>Automatic test discovery and running</h3>
<p>We specified a collection of tests above (dog_test.py).  But we<br />
will be writing a lot of tests, and we want to be able to run all<br />
of them in one shot.  We are going to use the &#8216;nose&#8217; test<br />
discovery and execution tool to find and run our tests.</p>
<div class="code">
<pre><em><span class="code-comment"># setup.py
</span></em>setup(...
     test_suite=<span class="code-string"><strong>"nose.collector"</strong></span><strong></strong>,
     tests_require=<span class="code-string"><strong>"nose"</strong></span><strong></strong>,
     )</pre>
</div>
<p>The <tt>tests_require</tt> line will make easy_install download and put nose in<br />
the current directory if <tt>nose</tt> is not already installed.</p>
<pre class="wiki">$ python setup.py test
... &lt;downloads nose&gt;

...
test_greeting (tests.dog_test.DogTest) ... ok
...</pre>
<p>(If it fails the first time; just run <tt>python setup.py test</tt> again.)</p>
<h3>The main function</h3>
<p>We have a speaker library, but we don&#8217;t have a &#8220;main&#8221; script<br />
yet.  You often have to create a separate file just for the<br />
&#8220;main&#8221; script, which is (should be) just a wrapper script that<br />
imports some module and calls a function in it.  In fact, for a<br />
large package, we may have many &#8220;main&#8221; scripts, each doing<br />
nothing more than importing the required packages and modules and<br />
calling some function in there.</p>
<p>We can use the setuptools &#8216;Entry points&#8217; mechanism for this.  An<br />
&#8216;entry point&#8217; is the name of some functionality of the<br />
package/application; entry points come in groups; two groups are<br />
pre-defined: &#8220;console_scripts&#8221; and &#8220;gui_scripts&#8221;.  Setuptools can<br />
auto-generate wrapper scripts for our entry points.</p>
<p>Here is how we can tell setuptools to generate a console script<br />
that does something useful:</p>
<div class="code">
<pre><em><span class="code-comment"># setup.py
</span></em>setup(...
      entry_points={
        <span class="code-string"><strong>'console_scripts'</strong></span><strong></strong>: [
            <span class="code-string"><strong>'rundog = speaker.dog:DogMain'</strong></span><strong></strong>,
            ],
        },
     ...
     )</pre>
</div>
<p>Now, when we do a <tt>python setup.py develop</tt>, or a user installs<br />
our egg, a script called &#8216;rundog&#8217; will be generated and<br />
automatically put somewhere in the path.  The script will called<br />
the <tt>DogMain</tt> function in the <tt>speaker.dog</tt> module with no<br />
arguments, and the return value of the function will be the<br />
exit status of the script.</p>
<p>What would the <tt>DogMain</tt> function be like?</p>
<div class="code">
<pre><em><span class="code-comment"># speaker/dog.py
</span></em>...
<strong><span class="code-lang">def</span></strong> <strong><span class="code-func">DogMain</span></strong>():
    d = Dog()
    <strong><span class="code-lang">print</span></strong> d.greeting()
    <strong><span class="code-lang">return</span></strong> 0</pre>
</div>
<p>Now, when we run &#8216;develop&#8217; again, setuptools will generate the <tt>rundog</tt> script<br />
for us:</p>
<pre class="wiki">$ python setup.py develop
...
Installing rundog script to .../bin
...
$ rundog
Bow, wow!</pre>
<p>We should keep a minimum amount of code in <tt>DogMain</tt> and put most<br />
of it in discrete, well tested functions.  This helps make code<br />
more robust and re-usable.</p>
<h3>About version numbers</h3>
<p>Until now, other projects using our Speaker package have been<br />
checking out code from our code repository and using it directly.<br />
Now it is time to make an &#8216;official&#8217; release.  We shall release<br />
v0.1 (the version we have been working on, and the one specified<br />
in setup.py) of our package (and remove &#8216;dev&#8217; from the release<br />
name).  For easy_install:</p>
<p>0.1a &lt; 0.1b &#8230; &lt; 0.1dev &lt; <strong>0.1</strong> &lt; 0.1-1 &lt; 0.1-2 &#8230;</p>
<p>Steps:</p>
<ol>
<li>We create a release branch</li>
<li>On the release branch, we edit <tt>setup.cfg</tt>.  Currently, it probably says:
<pre class="wiki">[egg_info]
tag_build = dev</pre>
</li>
<li>We change it to:
<pre class="wiki">[egg_info]
tag_build =</pre>
</li>
<li>Now we can generate a &#8216;release&#8217; version and copy it to some download page.
<pre class="wiki">$ python setup.py sdist bdist_egg
$ ls dist/
Speaker-0.1-py2.5.egg  Speaker-0.1.tar.gz</pre>
</li>
<li>Back on the main branch, we prepare to work on the next version by<br />
changing the version number in <tt>setup.py</tt> to 0.2.</li>
<li>Our main branch releases are now &#8216;0.2dev&#8217;:
<pre class="wiki">$ python setup.py sdist bdist_egg
$ ls dist/
Speaker-0.2dev-py2.5.egg  Speaker-0.2dev.tar.gz</pre>
</li>
</ol>
<h3>Post releases</h3>
<p>So, we have released v0.1 of Speaker.  However, there is a bug:<br />
there is no README.txt!  This bug has just been fixed on the<br />
trunk.  The trunk is not going to be stable until the next<br />
release, which is a month away, and we have to release<br />
a bugfix NOW!</p>
<p>Steps:</p>
<ol>
<li>We checkout the release branch;</li>
<li>We cherry pick the desired commit from trunk to our release branch;</li>
<li>We edit <tt>setup.cfg</tt> in the release branch and add a post-release tag:
<pre class="wiki">[egg_info]
tag_build = -1
tag_svn_revision = false</pre>
</li>
<li>We make a new release:
<pre class="wiki">$ python setup.py sdist bdist_egg
$ ls dist/
Speaker-0.1_1-py2.5.egg  Speaker-0.1-1.tar.gz</pre>
</li>
<li>And tag the new release (we always tag outgoing stuff)</li>
</ol>
<p>And now we have a bugfix update to our 0.1 release.  If we upload<br />
it to the distribution dir, easy_install will pick it in<br />
preference to the older 0.1 release.</p>
<h3>Defining dependencies</h3>
<p>We are probably going to be using a bunch of libraries when<br />
developing our project.  We can define a dependency requirement<br />
like this:</p>
<div class="code">
<pre><em><span class="code-comment"># setup.py
</span></em>setup(...
     install_requires=[<span class="code-string"><strong>"SQLAlchemy"</strong></span><strong></strong>],
     ...
     )</pre>
</div>
<p>Now, when we do a <tt>python setup.py develop</tt>, or a user installs<br />
our egg, easy_install will find the latest version of SQLAlchemy<br />
from PyPI, download it, and install it.</p>
<p>Other projects can depend on our Speaker project in the same way.</p>
<h3>Restricting dependency versions</h3>
<p>Let&#8217;s say we know that SQLAlchemy has a stable 0.4 branch, and 0.5 beta in<br />
progress.  We don&#8217;t want 0.5 beta versions.  How do we tell<br />
setuptools to install the highest 0.4 version, but not any 0.5<br />
version?</p>
<p>First, we have to find out what the smallest version on the 0.5<br />
branch is.  Then we need to chenge our requirement to:</p>
<pre class="wiki">SQLAlchemy &lt; 0.5.0a</pre>
<p>Where &#8220;0.5.0a&#8221; refers to the first version ever of the 0.5<br />
branch.  (This version does not have to exist; it should just be<br />
smaller than the smallest version you want to ignore.)  One needs<br />
to be quite careful about choosing the right version number.<br />
Saying only 0.5, or only 0.5.0, would not not have worked, because 0.5.0rc1<br />
is &#8220;smaller&#8221; than 0.5.0 or 0.5!</p>
<p>Let&#8217;s say we know that our stuff works with 0.4.3 and higher<br />
versions of SQLAlchemy, but does not work with 0.4.2 or below.<br />
Our requirement can look like this:</p>
<pre class="wiki">SQLAlchemy &gt;= 0.4.3, &lt; 0.5.0a</pre>
<p>Also, note that:</p>
<ul>
<li>If a version of SQLAlchemy is installed system wide that<br />
satisfies the dependency version requirement, easy_install<br />
will download and install that version.  Hence, we should<br />
avoid polluting the system python site-packages.</li>
</ul>
<ul>
<li>Easy_install will not upgrade your dependency automatically<br />
when you run it later, even if a newer version of the<br />
dependency is available, as long as the installed version<br />
satisfies your dependency version requirement.</li>
</ul>
<h3>Dependencies not on PyPI</h3>
<p>What if the library we need is not on PyPI?  What if it is<br />
actually developed and packaged by another group in our company,<br />
and available only from an internal release page?</p>
<p>We can get dependencies like these by telling setuptools to look<br />
at a particular URL.</p>
<div class="code">
<pre><em><span class="code-comment"># setup.py
</span></em>setup(...
      install_requires=[
        <span class="code-string"><strong>"SQLAlchemy &gt;0.4.3, &lt;0.5.0a"</strong></span><strong></strong>, <em><span class="code-comment"># On PyPI
</span></em>        <span class="code-string"><strong>"hello"</strong></span><strong></strong>, <em><span class="code-comment"># An Affle package
</span></em>      ],
      dependency_links = [
        <span class="code-string"><strong>"file:///home/parijat/Python/"</strong></span><strong></strong> <em><span class="code-comment"># find Affle packages here

</span></em>        ],
     )</pre>
</div>
<p>Now setuptools will look first in <tt>/home/parijat/Python</tt>.  If<br />
hello and SQLAlchemy eggs are there, it will use them.  If an egg of<br />
the eggs is not found there, then it will go to PyPI.</p>
<p>More than one dependency link can be specified.</p>
<h2>Developing binary eggs (C extensions)</h2>
<p>Now we come to the interesting bit: binary packages.  We can use<br />
the Python C API to write extension modules, and let distutils<br />
build them.  But there are easier ways.</p>
<h2>Version 0.2: Pyrex extensions</h2>
<p><a class="ext-link" href="http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/"><span class="icon">Pyrex</span></a> is &#8220;a Language for Writing Python Extension Modules&#8221;.  The<br />
greatest benefit is that Pyrex makes it easy to convert types<br />
between Python and C.</p>
<h3>Writing extensions in Pyrex</h3>
<p>We&#8217;ll demonstrate this with a new speaker class, and we shall choose <tt>Gendibal</tt><br />
for this task.  Here is the interface to <tt>Gendibal</tt>:</p>
<div class="code">
<pre><em><span class="code-comment"># tests/gendibal_test.py
</span></em><strong><span class="code-lang">import</span></strong> unittest

<strong><span class="code-lang">from</span></strong> speaker <strong><span class="code-lang">import</span></strong> gendibal

<strong><span class="code-lang">class</span></strong> GendibalTest(unittest.TestCase):
    <strong><span class="code-lang">def</span></strong> <strong><span class="code-func">test_greeting</span></strong>(self):
        g = gendibal.Gendibal()
        self.assert_(g.greeting() == <span class="code-string"><strong>"Hello 29"</strong></span><strong></strong>)</pre>
</div>
<p>Gendibal is a mathematical speaker, and happens to like the 10th<br />
prime number a lot.  Now we only have to define the Gendibal class:</p>
<div class="code">
<pre><em><span class="code-comment"># speaker/gendibal.pyx
</span></em>...
<strong><span class="code-lang">class</span></strong> Gendibal(object):
    <strong><span class="code-lang">def</span></strong> <strong><span class="code-func">greeting</span></strong>(self):
        <strong><span class="code-lang">return</span></strong> <span class="code-string"><strong>"Hello %s"</strong></span><strong></strong> % primes(10)[-1]

<strong><span class="code-lang">def</span></strong> <strong><span class="code-func">GendibalMain</span></strong>():
    g = Gendibal()
    <strong><span class="code-lang">print</span></strong> g.greeting()
    <strong><span class="code-lang">return</span></strong> 0</pre>
</div>
<p>and add a new entry point:</p>
<div class="code">
<pre><em><span class="code-comment"># setup.py
</span></em>setup(...
      entry_points={
        <span class="code-string"><strong>'console_scripts'</strong></span><strong></strong>: [
            <span class="code-string"><strong>'rundog = speaker.dog:DogMain'</strong></span><strong></strong>,
            <span class="code-string"><strong>'rungendibal = speaker.gendibal:GendibalMain'</strong></span><strong></strong>,
            ],
        },
     ...
     )</pre>
</div>
<p><strong>Note:</strong></p>
<ul>
<li>the definition of this class is in a file with the <strong><tt>.pyx </tt></strong>suffix, indicating that this is a Pyrex, not Python file.</li>
<li>the definition is a Python definition.  Pyrex code can contain normal Python code.</li>
</ul>
<p>We have not defined the <tt>primes</tt> function yet. Here is the definition of the<br />
<tt>primes</tt> function, in the same <tt>.pyx</tt> file:</p>
<div class="code">
<pre><em><span class="code-comment"># speaker/gendibal.pyx
</span></em>...
<strong><span class="code-lang">def</span></strong> <strong><span class="code-func">primes</span></strong>(int kmax):
  c<strong><span class="code-lang">def</span></strong> <strong><span class="code-func">int n, k, i

</span></strong>  c<strong><span class="code-lang">def</span></strong> <strong><span class="code-func">int p[1000]
</span></strong>  result = []
  <strong><span class="code-lang">if</span></strong> kmax &gt; 1000:
    kmax = 1000
  k = 0
  n = 2
  <strong><span class="code-lang">while</span></strong> k &lt; kmax:
    i = 0
    <strong><span class="code-lang">while</span></strong> i &lt; k <strong><span class="code-lang">and</span></strong> n % p[i] &lt;&gt; 0:
      i = i + 1
    <strong><span class="code-lang">if</span></strong> i == k:
      p[k] = n
      k = k + 1
      result.append(n)
    n = n + 1
  <strong><span class="code-lang">return</span></strong> result</pre>
</div>
<p>This is Pyrex code.  It looks very much like Python, with some type annotations.</p>
<h3>Building Pyrex extensions</h3>
<p>Setuptools can build Pyrex files &#8220;out of the box&#8221;, as long as the<br />
Pyrex compiler is somewhere on the path.  Let&#8217;s get Pyrex:</p>
<pre class="wiki">$ easy_install pyrex</pre>
<p>We need to tell setuptools about our extension, though:</p>
<div class="code">
<pre><em><span class="code-comment"># setup.py
</span></em><strong><span class="code-lang">from</span></strong> setuptools <strong><span class="code-lang">import</span></strong> setup, find_packages, Extension
...
setup(...
      ext_modules=[
        Extension(<span class="code-string"><strong>'speaker.gendibal'</strong></span><strong></strong>, [<span class="code-string"><strong>'speaker/gendibal.pyx'</strong></span><strong></strong>]),
        ],
     ...
     )</pre>
</div>
<p>And that&#8217;s it! We can build the egg:</p>
<pre class="wiki">$ python setup.py bdist_egg
...
running build_ext
pyrexc speaker/gendibal.pyx --&gt; speaker/gendibal.c
...
gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.5 -c speaker/gendibal.c -o build/temp.linux-i686-2.5/speaker/gendibal.o
gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions
build/temp.linux-i686-2.5/speaker/gendibal.o -o
build/lib.linux-i686-2.5/speaker/gendibal.so
...
creating stub loader for speaker/gendibal.so
byte-compiling build/bdist.linux-i686/egg/speaker/gendibal.py to
gendibal.pyc
...</pre>
<p><strong>Note:</strong></p>
<ul>
<li>The Pyrex code <tt>gendibal.pyx</tt> was converted to C code <tt>gendibal.c</tt> by the<br />
Pyrex compiler;</li>
<li>The extension <tt>gendibal.so</tt> was compiled;</li>
<li>A wrapper python script <tt>gendibal.py</tt> to load the extension was automagically<br />
created for us.</li>
</ul>
<p>Now there are two tests:</p>
<pre class="wiki">$ python setup.py test
...
test_greeting (tests.dog_test.DogTest) ... ok
test_greeting (tests.gendibal_test.GendibalTest) ... ok
...</pre>
<p>Wasn&#8217;t it handy we are using &#8216;nose&#8217;?  Our new test is discovered<br />
and run for us without having to add it anywhere.</p>
<p>We can run our new &#8216;main&#8217; script:</p>
<pre class="wiki">$ rungendibal
Hello 29</pre>
<p>Pyrex can not only be used to convert Python code to C, but it<br />
can help us interface to existing C code/libraries.</p>
<h2>Version 0.3: Boost.Python extensions</h2>
<p>What about libraries/code in C++?  Pyrex does not help there, and<br />
wrapping around C++ code with Python C API can be tricky.<br />
<a class="ext-link" href="http://www.boost.org/doc/libs/1_36_0/libs/python/doc/index.html"><span class="icon">Boost.Python to the rescue.</span></a></p>
<h3>Writing extensions in Boost.Python</h3>
<p>Let&#8217;s say we have the following C++ library:</p>
<div class="code">
<pre># <strong><span class="code-keyword">speaker/bjarne.cpp</span></strong>
#<strong><span class="code-keyword">include</span></strong> <span class="code-string"><strong>&lt;string&gt;</strong></span><strong></strong>
#<strong><span class="code-keyword">include</span></strong> <span class="code-string"><strong>&lt;iostream&gt;</strong></span><strong></strong>

namespace { <em><span class="code-comment">// Avoid clutering the global namespace
</span></em>    <span class="code-type"><strong>class</strong></span><strong></strong> BjarneCPP {
    <span class="code-type"><strong>public</strong></span><strong></strong>:
        std::string greet() <span class="code-type"><strong>const</strong></span><strong></strong> { <strong><span class="code-lang">return</span></strong> <span class="code-string"><strong>"Hello, C++ World!"</strong></span><strong></strong>; }
    };

    <span class="code-type"><strong>int</strong></span><strong></strong> BjarneCPPMain() {
        BjarneCPP b = BjarneCPP();
        std::cout &lt;&lt; b.greet() &lt;&lt; std::endl;
    }
}</pre>
</div>
<p>As can be seen, there is a class named <tt>BjarneCPP</tt> with an<br />
interface very similar to our speaker interface, except that it<br />
has a <tt>greet</tt> method, instead of our usual <tt>greeting</tt> method.<br />
There is also a <tt>BjarneCPPMain</tt> function, that looks like a good<br />
candidate to be a <tt>main</tt> function in our application.  This looks like a useful<br />
library.  How do we access it in Python?</p>
<p>We can wrap it in Python like this:</p>
<div class="code">
<pre># <strong><span class="code-keyword">speaker/bjarne.cpp</span></strong>
...
#<strong><span class="code-keyword">include</span></strong> <span class="code-string"><strong>&lt;boost/python.hpp&gt;</strong></span><strong></strong>
using namespace boost::python;

<strong><span class="code-func">BOOST_PYTHON_MODULE</span></strong>(bjarne) {
    class_&lt;BjarneCPP&gt;(<span class="code-string"><strong>"Bjarne"</strong></span><strong></strong>, init&lt;&gt;())
        .def(<span class="code-string"><strong>"greeting"</strong></span><strong></strong>, &amp;BjarneCPP::greet)
        ;
    def(<span class="code-string"><strong>"BjarneMain"</strong></span><strong></strong>, BjarneCPPMain, <span class="code-string"><strong>"The main function for 'bjarne'' module"</strong></span><strong></strong>);
}</pre>
</div>
<p>(For convenience and brevity, we&#8217;ve added our code in the same file.<br />
Realistically, the code to be wrapped would be in a library, and<br />
we would link against that library at build time.)</p>
<p>As usual, we do not forget to write our tests:</p>
<div class="code">
<pre><em><span class="code-comment"># tests/bjarne_test.py
</span></em><strong><span class="code-lang">import</span></strong> unittest
<strong><span class="code-lang">from</span></strong> speaker <strong><span class="code-lang">import</span></strong> bjarne

<strong><span class="code-lang">class</span></strong> BjarneTest(unittest.TestCase):
    <strong><span class="code-lang">def</span></strong> <strong><span class="code-func">test_greeting</span></strong>(self):
        b = bjarne.Bjarne()
        self.assert_(b.greeting() == <span class="code-string"><strong>"Hello, C++ World!"</strong></span><strong></strong>)</pre>
</div>
<p>and define an entry point:</p>
<div class="code">
<pre><em><span class="code-comment"># setup.py
</span></em>...
setup(...
      entry_points={
        <span class="code-string"><strong>'console_scripts'</strong></span><strong></strong>: [
            ...
            <span class="code-string"><strong>'runbjarne = speaker.bjarne:BjarneMain'</strong></span><strong></strong>,
            ],
      ...
      )</pre>
</div>
<h3>Building Boost.Python extensions</h3>
<p>Now we need to tell setuptools about the new extension:</p>
<div class="code">
<pre><em><span class="code-comment"># setup.py
</span></em>...
setup(...
     ext_modules=[
     ...
        Extension(<span class="code-string"><strong>'speaker.bjarne'</strong></span><strong></strong>,
                  [<span class="code-string"><strong>'speaker/bjarne.cpp'</strong></span><strong></strong>],
                  libraries=[<span class="code-string"><strong>'boost_python'</strong></span><strong></strong>]),
        ],
     ...
     )</pre>
</div>
<p>And that&#8217;s it.  We can create an egg:</p>
<pre class="wiki">$ python setup.py bdist_egg
...
building 'speaker.bjarne' extension
gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.5 -c speaker/bjarne.cpp -o build/temp.linux-i686-2.5/speaker/bjarne.o
...
g++ -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-i686-2.5/speaker/bjarne.o -lboost_python -o build/lib.linux-i686-2.5/speaker/bjarne.so
...
creating stub loader for speaker/bjarne.so
...
byte-compiling build/bdist.linux-i686/egg/speaker/bjarne.py to bjarne.pyc
...</pre>
<p>Again, setuptools has compiled our extension module, linked it<br />
against the libraries specified (<tt>boost_python</tt>), and generated a<br />
wrapper (&#8216;bjarne.py&#8217;) for us.</p>
<p>We can run our tests, and our new test will appear:</p>
<pre class="wiki">$ python setup.py test
...
test_greeting (tests.bjarne_test.BjarneTest) ... ok
test_greeting (tests.dog_test.DogTest) ... ok
test_greeting (tests.gendibal_test.GendibalTest) ... ok
...</pre>
<p>And our new entry point works too:</p>
<pre class="wiki">$ runbjarne
Hello, C++ World!</pre>
<h2>easy_install annoyances</h2>
<ul>
<li>easy_install does not upgrade dependencies when upgrading a<br />
package;</li>
<li>easy_install does not, by itself, have a way of specifying<br />
exact versions of all dependencies of a package;</li>
<li>it is possible to force easy_install to not download anything<br />
from the Internet but to install everything from a given<br />
location; this can be used to mitigate unexpected versions of<br />
dependencies being installed;</li>
<li>easy_install, by itself, will install packages in the<br />
system-wide python site-packages directory; this can be a big<br />
annoyance. It is highly recommended to use <tt>virtualenv</tt>.</li>
</ul>
<h2>Credits</h2>
<p>Egg jargon/terminology taken from: http://grok.zope.org/documentation/tutorial/introduction-to-zc.buildout.</p>
 Tagged: boost.python, easy_install, eggs, packaging, pyrex, python, setuptools <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/parijatmishra.wordpress.com/141/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/parijatmishra.wordpress.com/141/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/parijatmishra.wordpress.com/141/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/parijatmishra.wordpress.com/141/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/parijatmishra.wordpress.com/141/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/parijatmishra.wordpress.com/141/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/parijatmishra.wordpress.com/141/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/parijatmishra.wordpress.com/141/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/parijatmishra.wordpress.com/141/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/parijatmishra.wordpress.com/141/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=parijatmishra.wordpress.com&blog=3282491&post=141&subd=parijatmishra&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://parijatmishra.wordpress.com/2008/10/08/python-packaging-setuptools-and-eggs/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/e3aba44539a78ea92373418456f090e3?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">pm</media:title>
		</media:content>
	</item>
	</channel>
</rss>