TiffImagePlugin.ImageFileDirectory.__getattr__ is magical because it deletes items from "tagdata" variable and this plays badly with TiffImagePlugin.ImageFileDirectory.__iter__. Under Python 2.x items() returned a list and this wasn't a problem (because __iter__ value was evalued once); under Python 3.x items() returns a view/iterator that chains self.tags and self.tagdata and iteration begins to fail with "RuntimeError: dictionary changed size during iteration" exception because tagdata item is modified.
In this changeset I've tried to fix this by evaluating items() when the loop starts (by casting it to list), so that it doesn't matter if tagdata is changed during iteration or not.
There is no tests because _getexif is currently private. But this method is used by easy-thumbnails and sorl.thumbnails, so I think it is worth fixing it.
The EPS encoder wasn't part of Gohlke's test suite, so the previous "fixes"
there were only expected syntactic ones. This gives a cleaner fix to the
encoder.
The decoder doesn't work in round-trip due to a missing eps_decoder method
on the core module, but it's clear it worked at some point.
There are two main issues fixed with this commit:
* bytes vs. str: All file, image, and palette data are now handled as
bytes. A new _binary module consolidates the hacks needed to do this
across Python versions. tostring/fromstring methods have been renamed to
tobytes/frombytes, but the Python 2.6/2.7 versions alias them to the old
names for compatibility. Users should move to tobytes/frombytes.
One other potentially-breaking change is that text data in image files
(such as tags, comments) are now explicitly handled with a specific
character encoding in mind. This works well with the Unicode str in
Python 3, but may trip up old code expecting a straight byte-for-byte
translation to a Python string. This also required a change to Gohlke's
tags tests (in Tests/test_file_png.py) to expect Unicode strings from
the code.
* True div vs. floor div: Many division operations used the "/" operator
to do floor division, which is now the "//" operator in Python 3. These
were fixed.
As of this commit, on the first pass, I have one failing test (improper
handling of a slice object in a C module, test_imagepath.py) in Python 3,
and three that that I haven't tried running yet (test_imagegl,
test_imagegrab, and test_imageqt). I also haven't tested anything on
Windows. All but the three skipped tests run flawlessly against Pythons
2.6 and 2.7.
int() is really now long() in py3k, but to avoid breaking 2.6/2.7, we leave
the integer types where they are and just map long to int in py3k.
Also, pretty proud of myself for finding an easy way of detecting py3k.
This is, I guess, a few things the Python devs were just fed up with.
* "while 1" is now "while True"
* Types are compared with isinstance instead of ==
* Sort a list in one go with sorted()
My own twist is to also replace type('') with str, type(()) with tuple,
type([]) with list, type(1) with int, and type(5000.0) with float.
In py3k, imports are absolute unless using the "from . import" syntax.
This commit also solves a recursive import between Image, ImageColor, and
ImagePalette by delay-importing ImagePalette in Image.
I'm not too keen on this commit because the syntax is ugly. I might go back
and prefer the prettier "from PIL import".
What's really going on is that map() and filter() return iterators in py3k.
I've just gone ahead and turned them all into list comprehensions, because
I find them much easier to read.
y.has_key(x) is gone (use x in y), and keys(), values(), items(), and
range() all return views.
Some iterables needed to be packed into lists, either because the code
expected a list (such as "range(256) * 3") or because the original
collection was being modified (automatic global declarations).
The Tiff ImageFileDictionary is a special case and will be dealt with in
another commit.
Most of the differences are in tobytes/tostring naming and expected
behavior of the bytes() constructor. The latter was usually easy to fix
with the right bytes literal.
This is a good preview of what will have to happen in the Python 3 code.
This commit:
* Adds Python 3 module initialization functions. I split out the main init
of each module into a static setup_module function.
* Adds a py3.h which unifies int/long in Python 3 and unicode/bytes in
Python 2. _imagingft.c unfortunately looks a little kludgy after this
because it was already using PyUnicode functions, and I had to mix and
match there manually.
With this commit, the modules all build successfully under Python 3.
What this commit does NOT do is patch all of the uses of PyArg_ParseTuple
and Py_BuildValue, which all need to be checked for proper use of bytes
and unicode codes. It also does not let selftest.py run yet, because there
are probably hundreds of issues to fix in the Python code itself.