[Patch] PIL / setuptools compatibility

Laurence Rowe <[email protected]>
Newsgroups gmane.comp.python.image
Message-ID <[email protected]>
Hi,

Following the thread on Pillow and Zope / PIL compatibility, I think I've
found a solution that I hope will be acceptable for PIL.

Problem
=======

It's not really a Zope / PIL issue, but rather an easy_install / PIL one which
I think exposes a minor problem with PIL's setup.py which only shows up when
installing with easy_install::

    $ tmp/bin/easy_install http://effbot.org/downloads/Imaging-1.1.7.tar.gz
    ...
    Installed /data/devel/pil/tmp/lib/python2.6/site-packages/PIL-1.1.7-py2.6-macosx-10.6-i386.egg
    Processing dependencies for PIL==1.1.7
    Finished processing dependencies for PIL==1.1.7

We're unable to ``import PIL``::

    $ tmp/bin/python
    Python 2.6.4 (r264:75706, Jan 26 2010, 20:09:19)
    >>> import PIL
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ImportError: No module named PIL
    >>> import Image
    >>>

When the egg is created by easy_install the contents are not within a PIL
subdirectory::

    $ ls tmp/lib/python2.6/site-packages/PIL-1.1.7-py2.6-macosx-10.6-i386.egg
    ArgImagePlugin.py	ImageEnhance.py		PalmImagePlugin.pyc
    ArgImagePlugin.pyc	ImageEnhance.pyc	PcdImagePlugin.py
    BdfFontFile.py		ImageFile.py		PcdImagePlugin.pyc
    ...

However, if we install without easy_install we get instead::

    $ tar -zxf ~/Downloads/Imaging-1.1.7.tar.gz
    $ tmp/bin/python Imaging-1.1.7/setup.py install
    ...
    running install_lib
    creating /data/devel/pil/tmp/lib/python2.6/site-packages/PIL
    ...
    running install_egg_info
    Writing /data/devel/pil/tmp/lib/python2.6/site-packages/PIL/PIL-1.1.7-py2.6.egg-info
    creating /data/devel/pil/tmp/lib/python2.6/site-packages/PIL.pth

And don't see a problem:

    $ tmp/bin/python
    Python 2.6.4 (r264:75706, Jan 26 2010, 20:09:19)
    >>> import PIL
    >>> import Image
    >>>

Why does this happen?
=====================

To enable ``import Image`` to work, PIL's setup.py installs `Image.py` and
with the following options::

    extra_path = "PIL",
    package_dir = {"": "PIL"},
    packages = [""],

As the `PIL` directory contains an `__init__.py`, ``from PIL import Image``
also works. This is a neat distutils hack, it just doesn't work for eggs.

How can this be fixed?
======================

Instead of making a subdirectory importable by magic, we can use a trick to
install PIL.pth::

    package_data = {"PIL": ["../PIL.pth"]},

This means the PIL package can be installed normally::

    ext_package = "PIL",
    packages = ["PIL"],

Everything still ends up in the same place when you install with setup.py::

    $ tmp/bin/python pil-setuptools-compat/setup.py install
    ...
    running build_py
    ...
    creating build/lib.macosx-10.6-i386-2.6/PIL
    ...
    copying PIL/../PIL.pth -> build/lib.macosx-10.6-i386-2.6/PIL/..
    running build_ext
    ...
    running install_lib
    creating /data/devel/pil/tmp/lib/python2.6/site-packages/PIL
    ...
    copying build/lib.macosx-10.6-i386-2.6/PIL.pth ->
/data/devel/pil/tmp/lib/python2.6/site-packages

    $ tmp/bin/python
    Python 2.6.4 (r264:75706, Jan 26 2010, 20:09:19)
    >>> import PIL
    >>> import Image
    >>>

But now when we install with easy_install::

    $ tmp/bin/easy_install pil-setuptools-compat/
    ...
    Installed /data/devel/pil/tmp/lib/python2.6/site-packages/PIL-1.1.7-py2.6-macosx-10.6-i386.egg
    Processing dependencies for PIL==1.1.7
    Finished processing dependencies for PIL==1.1.7

The egg gets created with a PIL package::

    $ ls tmp/lib/python2.6/site-packages/PIL-1.1.7-py2.6-macosx-10.6-i386.egg
    EGG-INFO	PIL		PIL.pth

And we can now import PIL::

    $ tmp/bin/python
    Python 2.6.4 (r264:75706, Jan 26 2010, 20:09:19)
    >>> import PIL
    >>> import Image
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ImportError: No module named Image
    >>>

The ``import Image`` fails, because the PIL.pth is not directly in
`site-packages`. This doesn't seem to be a concern for PIL users who install
with easy_install / buildout :)

To run the tests, I copied the test script and images to another folder for
the imports to work correctly::

    $ cd pil-setuptools-compat/
    $ cp -R selftest.py Images ../tmp/
    $ cd ../tmp/
    $ bin/python selftest.py
    --------------------------------------------------------------------
    PIL 1.1.7 TEST SUMMARY
    --------------------------------------------------------------------
    Python modules loaded from
/data/devel/pil/tmp/lib/python2.6/site-packages/PIL-1.1.7-py2.6-macosx-10.6-i386.egg/PIL
    Binary modules loaded from
/data/devel/pil/tmp/lib/python2.6/site-packages/PIL-1.1.7-py2.6-macosx-10.6-i386.egg/PIL
    --------------------------------------------------------------------
    --- PIL CORE support ok
    --- TKINTER support ok
    --- JPEG support ok
    --- ZLIB (PNG/ZIP) support ok
    --- FREETYPE2 support ok
    *** LITTLECMS support not installed
    --------------------------------------------------------------------
    Running selftest:
    --- 57 tests passed.


Code
====

Branch and test package at http://bitbucket.org/lrowe/pil-setuptools-compat


Sorry this has got so long! I wanted to avoid misunderstandings.

Laurence

_______________________________________________
Image-SIG maillist  -  [email protected]
http://mail.python.org/mailman/listinfo/image-sig
pil-setuptools-compat.diff (application/octet-stream, 996 B)
# HG changeset patch
# User Laurence Rowe <[email protected]>
# Date 1282527703 -3600
# Node ID af38417fd57a31fbc18e536f127fd5797b9a0089
# Parent  f356a1f64271e9d3206fcf9059492ba1c9e163d6
easy_install compatibility

diff -r f356a1f64271 -r af38417fd57a setup.py
--- a/setup.py	Sun Nov 15 19:03:47 2009 +0100
+++ b/setup.py	Mon Aug 23 02:41:43 2010 +0100
@@ -473,13 +473,13 @@
         cmdclass = {"build_ext": pil_build_ext},
         description=DESCRIPTION,
         download_url=DOWNLOAD_URL % (NAME, VERSION),
+        ext_package = "PIL",
         ext_modules = [Extension("_imaging", ["_imaging.c"])], # dummy
-        extra_path = "PIL",
+        package_data={"PIL": ["../PIL.pth"]},
         license="Python (MIT style)",
         long_description=DESCRIPTION,
         name=NAME,
-        package_dir={"": "PIL"},
-        packages=[""],
+        packages=["PIL"],
         platforms="Python 1.5.2 and later.",
         scripts = glob.glob("Scripts/pil*.py"),
         url=HOMEPAGE,
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.