virtualenv / pil pillow mess
Numerous articles have been written about why you want to install
Pillow instead of PIL to get the Python Imaging tools. Like
Problems with PIL? Use Pillow
instead!
(Find more by searching for “IOError: decoder zip not available
”.)
This note concerns something more insidious: a seemingly broken Pillow installation after the removal of PIL.
~$ mkvirtualenv piltest
(piltest)~$ pip install PIL
(piltest)~$ pip freeze | grep -i pil
PIL==1.1.7
Now this should work:
(piltest)site-packages$ python -c "import Image; im = Image.open('/lib/plymouth/ubuntu_logo.png'); im.load()"
Traceback (most recent call last):
File "<string>", line 1, in <module>
File ".../site-packages/PIL/ImageFile.py", line 189, in load
d = Image._getdecoder(self.mode, d, a, self.decoderconfig)
File ".../site-packages/PIL/Image.py", line 385, in _getdecoder
raise IOError("decoder %s not available" % decoder_name)
IOError: decoder zip not available
Ok. This still doesn’t work. This is why the “Problems with PIL? Use Pillow instead!“ articles exist. So. Time to switch to Pillow.
Let’s examine what happens when someone comes along and removes the
PIL
dir by hand. Perhaps because his pip is so old that it doesn’t
have an uninstall
option.
(piltest)~$ cdsitepackages
(piltest)site-packages$ rm -rf PIL
(piltest)site-packages$ pip freeze | grep -i pil
Excellent. No PIL installed. Let’s resume installing Pillow.
(piltest)site-packages$ pip install Pillow
(piltest)site-packages$ pip freeze | grep -i pil
Pillow==2.1.0
And yet, stuff is broken.
This works (like documented):
(piltest)site-packages$ python -c "from PIL import Image; im = Image.open('/lib/plymouth/ubuntu_logo.png'); im.load()"
But this — observe the lack of from PIL
in the import
statement —
seems to work, but breaks.
There is no nice ImportError
, but rather a runtime error after loading
a file. (Which of course happens right in the middle of a presentation.)
(piltest)site-packages$ python -c "import Image; im = Image.open('/lib/plymouth/ubuntu_logo.png'); im.load()"
Traceback (most recent call last):
File "<string>", line 1, in <module>
File ".../site-packages/PIL/Image.py", line 2008, in open
raise IOError("cannot identify image file")
IOError: cannot identify image file
That means that a construct like this would fail:
try:
import Image
except ImportError:
from PIL import Image
How did that happen?
Well, the devil is in the details. The rogue removal of the PIL
directory bypassed the removal of PIL.pth
. That pth
file is parsed
by the virtualenv custom site.py
—
~/.virtualenvs/piltest/lib/python2.7/site.py
. That, in turn, causes
the addition of the PIL
path in sys.path
which breaks proper
Pillow functioning.
A path configuration file is a file whose name has the form <package>.pth; its contents are additional directories (one per line) to be added to sys.path. Non-existing directories (or non-directories) are never added to sys.path; no directory is added to sys.path more than once. Blank lines and lines beginning with
'#'
are skipped. Lines starting with'import'
are executed.
The fix is to clear out PIL.pth
or remove it altogether.
(piltest)site-packages$ cat PIL.pth
PIL
(piltest)site-packages$ rm PIL.pth