I got a shiny new Linux desktop at work yesterday (yay!), and went about the wonderful adventure of setting up my development environment. Emacs - check. Firefox, Firebug - check. Pylons - here we go.
Here's my first issue: setuptools makes verbose, mixed-case, ugly directories. I don't like it making everything ugly. In fact, it makes it harder to develop with multiple versions of libraries than just using good old symlinks.
OK, so I'll confine it to it's own purgatory inside of ~/.ez/ where it can make UglyDirectoryNames-1.0.3c2b1-DEV/ to its heart's content.
Except... easy_install won't install to a directory that's not on my sys.path.
Excuse me? Let me deal with the sys.path, on my own time, and just do as you're told.
So far, my "easy" installation has consisted of:
apt-get python-setuptools - actually, this is the only easy step.
Making a ~/.ez/ directory for it to live in
Making a .pydistutils.cfg with a prefix=~/.ez in the [install] section. (Which, by the way, is wicked hard to find in Google.)
Finally, easy_install Pylons. easy_install complains about my PYTHONPATH. I tell it to shut up, yell at my workstation a bit, and try again. No luck.
Set up my $PYTHONPATH in my ~/.bashrc to include ~/.ez/lib/python2.5/gratuitously/deep/directory/structure/site-packages/
Start installing Pylons. Headers are missing: apt-get install build-essential and python-dev. Okay, not setuptools' fault.
Get all the way to WebHelpers, which requires setuptools 0.6c7, not the 0.6c6 that apt-get installed.
apt-get remove setuptools...
wget http://peak.telecommunity.com/dist/ez_setup.py
python ez_setup.py
alias obscenely_hard_install=easy_install
obscenely_hard_install Pylons
Now, parts of this is my own fault for not RTFHugeHTMLPage-ing. Yeah, I know there's some Unix or Python convention that easy_install is following in making a 'prefix' directory mean 'the first tiny bit of the prefix, not the bulk of the path that comes after the prefix'. So, can you make a --real-prefix setting? Oh, right, I can instead use --install-dir and --script-dir, both of which are not given nearly enough press by Google.
But can I nuke my easy_install installation to redo it with --install-dir and --script-dir without going through the same amount of pain? Forgive me if I'm not feeling enthusiastic about trying.
I'm just going to be disgruntled and write about it online instead. But, I'm also going to show how I prefer to do things.
A Better Way
Now, this only works if you have real symlinks. So, this is oriented towards, from general to specific, Linux, Debian and Ubuntu, but anything at least marginally POSIXy should work. OSX, for example, should be just fine.
Setting Up Your .bashrc
Inside of your .bashrc, you want to have:
- export PYTHONPATH=$PYTHONPATH:~/.pylibs
I like to have the directory hidden. Out of sight, out of mind; but still quick to get to when debugging.
Get Your Libraries
I also have a ~/libs or ~/.libs directory to actually put my copies of the upstream code. I like to leave it versioned so I can 'svn up' or 'hg pull' (etc etc) to get the newest revision. Within it, I'll create a directory for each module, and then pull down each version that I need - usually, trunk, plus at least one stable tag. So, now my directory structure is looking like:
~/.pylibs/
~/libs/
sqla/
trunk/
0.4.0/
django/
trunk/
queryset-refactor/
...
Symlink your Favorite Version
Like so:
- ln -s ~/libs/sqla/trunk/lib/sqlalchemy ~/.pylibs/
- ln -s ~/libs/django/queryset-refactor/django ~/.pylibs/
Switching Versions
You have two ways of switching versions: either environment-wide, or in your code. Changing the version in the environment works something like this:
- rm ~/.pylibs/django
- ln -s ~/libs/django/trunk/django ~/.pylibs/
In your code, do this instead:
- import sys
- sys.path.insert(0, "/home/adam/libs/django/trunk")
- import django
This should all be familiar to you if you use Python. So I guess I'm just saying... use what's familiar.
But - but - but...
But It's Not Cross-Platform!
True. There is probably a cross-platform solution that is much better, but I don't know it. I'd have written about that, but I can hardly write about things that I don't know exist.
But You Just Made This Up!
True.
But Setuptools is a Standard!
I just prefer Python's built-in packaging. Which is also a standard, sort of, just with shorter sys.paths and prettier directory names.
But this doesn't handle compiling C extensions!
This is actually a problem. I do run setup.py with those, but they're relatively few and far between. This is for your bread-and-butter pure-Python library.
Comments
467 spam comments omitted.
I am no longer accepting new comments.
Waylan Limberg
#1767, 2008-02-06T14:25:31Z
Another alternative (perhaps the one you didn't write about because you didn't know it exists) would be to use path (something.pth) files. The best description I've found is here. There's also a minimal example of how to use them for branches in the django docs here (which I contributed and probably why I seem to be the only one who remembers they're there). While path files are generally limited only to the site-packages directory, they are a cross-platform alternative to Symlinks. And, IMO, it's a lot easier to uncomment one line and comment another, than remove and add symlinks. On top of that, it is a Python standard; just not a very well documented one.
Interestingly, although I've never used it, setuptools can apparently do this for you with the develop command. Rather than creating an egg (and those ugly directory names), it just edits the path in the easy-install.pth file to point directly to your source code. Need to run a different branch of your code? If I understand the docs correctly, just run the command on that branch and it should update the path in the easy-install.pth file accordingly.
I'll be setting up my "shinny new Linux desktop" (actually, it's used, but new to me) within the next few days and will give the setup.py develop approach a try. I'll try to remember to report back here.
Suraj Barkale
#1770, 2008-02-06T15:03:17Z
.pth files rule :) and the best documentation of using .pth files is the addpackage() function in Lib/site.py
Adam Gomaa
#1771, 2008-02-06T15:11:42Z
Sigh, I know I'm still having the markdown problems.
...I'm lazy. Another thing for me to do during tonight's charpy meeting, I guess.
mikeal
#1772, 2008-02-06T16:04:05Z
Is there a reason you don't want these installed in to site-packages?
site-packages is kind of the place where all your third party modules get installed and I don't see why you want to change that.
Like the previous commenters, $ python setup.py develop , will create sym links an install the needed modules. It will also create sym links in the python bin for all the executable scripts in the package. The develop command is awesome and I really suggest you use it.
If you are going to stick with your method using sys.path.insert(0, path), you should always sys.path.pop(0) after you import the module to speed up new import lookup times. Once you import it once and it's in sys.modules it won't need to be in sys.path anymore.
Adam Gomaa
#1773, 2008-02-06T16:39:09Z
Haha, mikeal, have you looked at a setuptools-altered sys.path? One extra path isn't my problem... it's twleve that I have issues with.
I typically don't want them installed in site-packages because I don't want them installed at all. I just want them available for development - this is, after all, my development environment.
.pth files look pretty close... I'll take a look at them, thanks!
Adam Gomaa
#1786, 2008-02-07T08:29:44Z
As if this wasn't enough, now I dropped into a 'paster shell development.ini'... and the auto-imported 'model' package wan't even the right code... it was some old version installed by easy_install. It's not just ugly, it actively interferes with development. Sheesh.
Chris Calloway
#1792, 2008-02-07T19:55:55Z
Adam, check out virtualenv. You can easy_install it. :) After than, just virtualenv my_virtual_python_project to create a directory with its own bin/python and its own site-packages. You'll never have to pollute the site-packages of your python build again.
I just used it to build an environment for cpycom. The dispatchy, wsgiref, and docutils modules in my cpycom environment are totally isolated.
If you have an isolated development environment you need to build repeatedly, checkout the awesome virtualenv-like zc.buildout.
Matthew Marshall
#1793, 2008-02-07T23:19:07Z
I've been using this method too :)
To get extention modules to work build them by running "python setup.py build_ext -i" That'll drop the .so files in the same directory with the source files.
MWM