[PP4E cover]

PP4E: Updates Page


Last revised: June 2020

This page collects notes, updates, and examples related to the book Programming Python, 4th Edition (PP4E), to serve as supplemental resources for this book's readers. If this page's posts ever had a sequential ordering, it was either accidental or abandoned long ago. Today, items here are best accessed randomly using the topic groupings of the content lists below.

Note that there are only a few true errata (corrections) in the last list below, all of which were fixed in early reprints. If you're looking for a complete corrections list, or find a new issue you wish to report, please see the publisher's errata page for this book. That page automatically notifies me when new posts appear, and hosts both book notes and answers to reader questions not duplicated here.

Related Resources

For more book resources, be sure to also see the following external pages, some of which are newer than this page, and continue its mission:

Content Here

General Book Notes

Example-Specific Notes

Python Changes Since Publication

Supplemental Examples

Book Corrections



More Bonus Examples: Folders Sync, Calendar GUI

[May-5-14] New book-related example: Mergeall consists of a script and GUI that synchronize directory trees, and can provide both an incremental updates tool and a manual alternative to cloud storage. Mergeall's main script reuses a number of directory-processing examples that appear in the book's systems programming part. This program's coverage includes code and screenshots, but grew too long for inline treatment here, and was moved off page.

Click here to go to the Mergeall page

As you'll find on that page, Mergeall eventually was ported to Mac OS too, and packaged as both source code and standalone executables for Mac, Windows, and Linux. It's a realistically scaled project that's too large to cover in the book, but suggested as follow-up study for readers.

Update, 2017 For more book-related example code, see also the newer Frigcal calendar GUI example, which showcases Python's tkinter GUI library covered extensively in the book, and the even newer programs page, which leads to upgraded versions of many of the book's major examples—most notably, PyEdit, PyMailGUI, and PyGadgets.


Running Book Examples on Linux — and Mac OS

[May-5-14] I've recently begun running book examples on a Linux dual-boot system, under Fedora 20 and Gnome 3 (and later, Ubuntu). This is partly in response to the focus in Windows on clouds, subscriptions, advertising, and devices that are proprietary and seem intentionally crippled, but that's not what this note is about (see the related post).

So far, all the major GUI-based examples work well unchanged, with one minor exception: the script used to launch PyMailGUI after selecting from one of N email accounts contains an unfortunately nonportable and hardcoded Windows path. You may never encounter this; PyMailGUI can be run directly too—and is by the book's demo launchers—and this script is in part coded to work when PYTHONPATH has not been set to include the book's examples root. But to fix the account-selector script so it works on Linux too, in this book examples tree file:

.../PP4E/Internet/Email/PyMailGui/altconfigs/launch_PyMailGui.py
change the 2nd-from-last line from the first of the following to the second, in order to pick up the underlying platform's path separator portably:
os.environ['PYTHONPATH'] = r'..\..\..\..\..'                             # hmm; generalize me
os.environ['PYTHONPATH'] = '..%s..%s..%s..%s..' % ((os.path.sep,) * 4)   # hmm; generalize me
You may also want to change the last line from os.system('PyMailGui.py') to something like os.system('python3 PyMailGui.py') in order to force 3.X execution on Linux for the spawned PyMailGUI, but this depends on your system's links and configuration (Python Windows launcher settings don't apply in any event—you'll need to specialize this line's code per sys.platform if needed). There are undoubtedly other Linux portability issues in smaller book examples, especially those in the Systems section; more here as they surface. See also: tkinter Linux portability notes elsewhere on this page.

Update, 2018 Subsequent to this post, the book's major book examples were also ported to and run successfully on Mac OS. For a sampling of some of the issues this platform poses, both GUI-related and general, see the release notes of:

Each of the above programs is also available in source-code form that illustrates Mac coding. Python and tkinter may be relatively portable, but some platform-specific divergence is unavoidable. The Mac's richer GUI experience—including global toolbars, slide-down dialogs, and app state—implies unique coding requirements.


Python Email Package Surrogates Bug in 3.3.3, Fixed in 3.3.4

Short story: due to a temporary regression in Python's email package, you probably should not run the book's PyMailGUI email client on Python 3.3.3. Instead, use any other Python 3.X version—3.1 or 3.2; 3.3.0 through 3.3.2; 3.3.4 or later 3.3; or 3.4.0 or later 3.4.

The Regression in 3.3.3

[Mar-4-14] In 3.3.3 only, Python's email package changed in a way that broke this book's PyMailGUI. The break occurs when replying to or forwarding a message whose main body text contains a non-ASCII character that was encoded per base64 or quoted-printable in the original message. Such email messages worked fine in PyMailGUI from Pythons 3.1 through 3.3.2. In 3.3.3, though, a simple slanted quote or emdash suffices to cause problems; when such characters are present in the body text, PyMailGUI doesn't crash, but the message can't be sent, and the GUI displays an error dialog with text:

Send failed:
<class 'UnicodeEncodeError'>
'utf-8' codec can't encode character '\udce2' in position 688:
surrogates not allowed

This makes no sense, given that surrogates are supposed to be employed in the email package's new bytes API only—an API which PyMailGUI predates, and does not use in any way (PyMailGUI decodes message full-text to str text instead). The 3.3.3 email package must be mutating the already-decoded body text, and inserting surrogate Unicode escapes—something it absolutely should not do, and did not do until the 3.3.3 point release.

Timing: because the error occurs on Send in the Message.set_payload() call following the fix_text_required() workaround for an earlier email issue, a change in character-set output encoding logic is the prime suspect. Before this point, the fetched raw text of mails is correct (double-clicks show its original encoded form), as is the result of mail parsing (View, Reply, and Fwd all display correctly decoded text, including any non-ASCII characters). Both failing cases observed were attempting to encode text per UTF-8 plus base64 on Send. In any event, the next section makes this largely a moot point.

The Repair in 3.3.4

The good news is that this Python regression appears to have been present in just one point release, and was fixed quickly. It has been observed in 3.3.3 only (plus an early 3.4 beta which inherited the issue temporarily). It is not present in 3.3.2, and is fixed as of 3.3.4. Its repair was also propagated to later 3.4 prereleases. Since the latest official 3.3 and 3.4 downloads available at python.org—currently 3.3.4, 3.3.5rc2, and 3.4.0rc2—do not have the problem, its impact should be minimal.

PyMailGUI itself was coded for Pythons 3.1 and 3.2, current at book development time, but is known to work well through 3.4.0, apart from this temporary surrogates issue in 3.3.3. I use this program constantly, but only recently discovered the issue when using a newer 3.3.3 install. It's less than ideal for point releases to break working programs this way, of course, but mistakes happen, and programs like PyMailGUI have to mind the bleeding edge of Python releases more than most; book readers tend to prefer the latest Python either way.

For examples of other PyMailGUI breakages caused by Python email package changes, see the patch for item #3 on this page; it's been a potential source of problems with each new Python release installed. I've also observed some Windows line-break strangeness in recent email package versions (text is sometimes saved as one long line), but this is to be investigated. In the end, this makes for a reasonable lesson in itself: library dependencies are an unavoidable aspect of real-world software development.

Footnote: You can verify the Python version that PyMailGUI is using by clicking Write, entering the following program code in the Write window's main text area, and then clicking its Tools -> Run Code menu option; this is a feature of the PyEdit component, which runs the edited text as program code, and shows its output in the console window where PyMailGUI was launched (don't try that in Outlook...):

import sys
print(sys.version)

Update, 2018 PyMailGUI eventually broke its dependencies on the latest-and-greatest Python release by providing standalone executable packages for each major desktop platform. These "frozen" executables simplify installs and better integrate with platform GUI metaphors. Perhaps more importantly, by bundling specific and verified versions of Python and Tk, they grow immune to future changes in either. The downside of such packages is extra build complexity beyond this update's scope; see PyMailGUI's home page and build folder for more details.


How a Monkey Broke PyMailGUI... (Tk Unicode-Limit Patch)

Short story: Tk, the library underlying the tkinter GUI module used in book examples, does not currently support some Unicode characters. If unsupported characters may crop up, programs need to replace these for display to avoid possibly uncaught exceptions. PyMailGUI, PyEdit, and other book-related programs now do.

The Tk Unicode Issue

[Jan-16-14] After using the threaded PyMailGUI on a daily basis for 8 years (more than 3 in its latest 4th Edition form), a new issue cropped up when someone sent an email whose alternative text part contained a Unicode character not supported by the underlying Tk GUI library—character 🙊, which is Unicode codepoint U+1f64a and u'\U0001F64A' in Pythonese, the "Speak-No-Evil Monkey" character (no really; look it up). The Tk GUI system can't handle character codes over 16 bits like this one (technically, outside the "BMP"), and PyMailGUI relies on Tk's rendering prowess to do the right thing for Unicode, as described in the book; see pages 538-548.

As is, PyMailGUI reports the Tk error message in the console window and doesn't crash per se, but the GUI is partly disabled, because this error is raised and uncaught in a thread-exit callback, thus preventing a thread-busy lock from being released... which in turn disables future Loads, Views, Deletes, and Quits (in fact, Task Manager may be required to close the GUI on Windows, and similar elsewhere).

To do better, fetch this updated ViewWindows.py, and copy it into your book example tree's PP4E\Internet\Email\PyMailGUI folder. It simply catches the Tk library exception, displays a popup and stack trace, and continues, so that thread-busy locks are released. Search for "1.5" in the file for more on the changes; the too-large Unicode character also triggers a Tk exception in other places (e.g., viewing the text part later), but these are already caught and reported with popups, and don't impact thread locks.

More PyMailGUI Ideas

From the semi-related-topics department: additional PyMailGUI changes to support POP over SSL, SMTP over SSL/TLS, and POP servers that limit logins by time (thereby perhaps requiring a single persistent login instead of one login per transaction) are in progress, but are also suggested exercise. Accounts on outlook.com are one motivation for some of these mods. The first two (SSL/TLS) are now supported in Python's libs, but not yet in PyMailGUI; see Python manuals for usage details, and this related note on this page.

Update, 2016 For much more on the Tk Unicode limitation, see its later description in the Frigcal docs. That program confronts the same issue, in the context of calendars and events. This is most egregious to people who abuse emojis (hey—you know who you are!).

Update, 2017 The Tk Unicode limitation in PyMailGUI—and the PyEdit component it uses—was eventually addressed more globally in its standalone release available here. To fix, all non-BMP Unicode characters are now replaced with the Unicode replacement character � for display (until Tk supports more of Unicode, including emojis). There's more on the issue at large in standalone PyEdit's user guide; search for its "About emojis" notebox.

Update, 2018 Support for email servers that use or require SSL/TLS also eventually found its way into PyMailGUI's standalone release; see its change log and mailconfig files for details.


A Patch for Running PyMailGUI on Python 3.3 (and Later)

[Sep-15-13] Per the description elsewhere on this page, a Python 3.3 standard library change broke some email address displays of non-ASCII names in PyMailGUI, the largest example in the book. In short, the Python 3.3 email package's formataddr utility function now applies a new automatic MIME encoding for names, which it did not in the past—a curious and undocumented incompatible change, which did not account for display-oriented use cases, and can break code that worked well under Pythons 3.0 through 3.2 (including some in this book). Luckily, this is fairly easy to repair.

To apply and use the patch for this Python change, simply fetch the following two files, and copy them to the PP4E\Internet\Email\PyMailGui folder in your book examples tree, per the more detailed instructions in the first of these:

  1. py33patch.py—the patch to import, with self-test and docs
  2. SharedNames.py—replacement for this file with required patch import
The first file updates the email package to be backward compatible for the duration of the PyMailGUI program's run only. The second file, an existing part of PyMailGUI, is simply augmented to import the first. The first file also has additional documentation on the issue and its patch—see its comments for more details.

(And yes, this is a module-level example of what's called "monkey patching" today, though applying a new label to an old technique doesn't necessarily make it any more palatable...)

Update, Oct-15-13 There is a new 1.4 release of the book's examples package which incorporates the small Python 3.3 patch described above. Get the new examples release here, and read about its 3.3 (and later) changes here.

Update, Nov-26-13 It has now been verified that this patch and the 1.4 examples release also suffice to make the book examples described here work under Python 3.4, per its beta releases.

Update, Oct-1-15 It's now also been verified that this patch and the 1.4 examples release suffice to make the book examples mentioned here work under Python 3.5, per its final 3.5.0 release.

Update, 2018 Naturally, this patch was also present in PyMailGUI's later standalone release. This release used Python 3.5 in 2017 and still does; later 3.Xs are not compelling enough to offset revalidation and redistribution costs (despite the PR).


Default Port Numbers in Preview's webserver.py

[Aug-22-13] Because it is now officially an FAQ, this post includes the important bits from a dialog with a reader who was having trouble running the web examples in the preview chapter of the book. In short, on some machines you may need to change the hardcoded port number used in this script to something other than "80," and list it in the URL explicitly (and read ahead in the book itself to the full coverage of this subject in later sections).

> > -----Original Message-----
> > To: lutz@rmi.net
> > Subject: Programming Python 4th Ed
> > Date: Wed, 21 Aug 2013 13:49:19 +0100
> > 
> > Dear Sir
> > 
> > Programming Python 4th Edition.
> > I'm stuck on page 53. Example 1-30 runs ok but I can't get example 
> > 1-31 to reply. When I run the html script it lists the contents of 
> > 1-31, How do I get it to execute 1-31?
> > I am using Python 3.3 on Windows 7.
>
>  
> -----Original Message-----
> From: Mark Lutz [mailto:lutz@rmi.net] 
> Sent: 21 August 2013 17:14
> Subject: Re: Programming Python 4th Ed
> 
> There are too many things that can go wrong in the Web realm to offer advice
> based on your email (including but not limited to running the web server
> shown a page or two ahead).  My advice is to read ahead to the server side
> scripting chapter of the book for the full story on the Web/CGI domain.
>
>
> -----Original Message-----
> To: 'Mark Lutz' 
> Subject: RE: Programming Python 4th Ed
> Date: Thu, 22 Aug 2013 11:39:13 +0100
> 
> Hi Mark
> Thanks for your prompt reply. I followed your advice to read further.
> When I run Example 1-32 Pg56 webserver.py I get the following output:-
> 
> Python 3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:55:48) [MSC v.1600 32 bit (Intel)] on win32
> Type "copyright", "credits" or "license()" for more information.
> >>> ================================ RESTART================================
> >>> 
> Traceback (most recent call last):
>   File "C:\Users\...\Documents\AAAPROJECTS\COMPUTERSCIENCE\PYTHON\PROGPY33\C01\webserver.py", line 15, in 
>     srvrobj  = HTTPServer(srvraddr, CGIHTTPRequestHandler)
>   File "C:\Python33\lib\socketserver.py", line 430, in __init__
>     self.server_bind()
>   File "C:\Python33\lib\http\server.py", line 135, in server_bind
>     socketserver.TCPServer.server_bind(self)
>   File "C:\Python33\lib\socketserver.py", line 441, in server_bind
>     self.socket.bind(self.server_address)
> OSError: [WinError 10013] An attempt was made to access a socket in a way forbidden by its access permissions
> >>>
> 
> Could you please help me with "socket access permissions" as I am new to web
> programming. This is the reason I purchased your book to extend my Python
> Programming into web applications.
> 
> I am running on my own Dell desktop as administrator using Windows 7
> Internet Explorer 10.
> 

The webserver script works fine for me on Python 3.3 and Windows7.
Running the server in a Command Prompt window:

  c:\PP4E\Examples\PP4E\Preview> py -3.3 webserver.py
  127.0.0.1 - - [22/Aug/2013 09:04:08] code 404, message File not found
  127.0.0.1 - - [22/Aug/2013 09:04:08] "GET /favicon.ico HTTP/1.1" 404 -
  127.0.0.1 - - [22/Aug/2013 09:04:17] "POST /cgi-bin/cgi101.py HTTP/1.1" 200 -
  127.0.0.1 - - [22/Aug/2013 09:04:17] command: C:\Python33\python.exe -u 
  c:\PP4E\Examples\PP4E\Preview\cgi-bin\cgi101.py ""
  127.0.0.1 - - [22/Aug/2013 09:04:17] CGI script exited OK

And responding to this URL typed in a web browser window:

  http://localhost/cgi101.html

Probably, you cannot run a server on port #80 (the script's default)
on your machine, because it is locked down by something else (e.g., 
virus software?).  Try changing the port# in the webserver script,
and then name the port# in the URL explicitly: 

  port = 8080   # default http://localhost/, else use http://localhost:xxxx/

  c:\PP4E\Examples\PP4E\Preview> py -3.3 webserver.py

  http://localhost:8080/cgi101.html

Or, pass the port# in on the command line to the expanded version 
of this script that appears later in the book, and run the examples
in that later section's directory: 

  c:\PP4E\Examples\PP4E\Internet\Web> py -3.3 webserver.py . 8080
  webdir ".", port 8080
  ...server log...

  http://localhost:8080/languages.html

This is all explained in detail later in the book in the 
server-side scripting chapter.  It's also mentioned in the 
preview chapter you're reading; quoting from page 57:

"""
One pragmatic note here: you may need administrator privileges 
in order to run a server on the script’s default port 80 on some
platforms: either find out how to run this way or try running on 
a different port.  To run this server on a different port, change
the port number in the script and name it explicitly in the URL 
(e.g., http://localhost:8888/).  We’ll learn more about this 
convention later in this book.
"""

If changing port #s doesn't suffice, I'm afraid there's
nothing more I can offer; server setup is widely variable,
and may require some supplemental exploration.

Best wishes,
--Mark Lutz  (http://learning-python.com, http://rmi.net/~lutz)


PyMailGUI: Enhancements Summary, Screenshots

Short story: this section includes a now-dated summary of post-publication changes to PyMailGUI, followed by updates on that program's later evolution. Be sure to also see this section's updates ahead for more recent information.

PyMailGUI Post-Publication Changes Summary

[Oct-1-11] After using the book's PyMailGUI email client for just over a year, I've collected a list of additional enhancements beyond those already described in the book (see the original enhancements list at the end of PyMailGUI's Chapter 14). I am the entire testing department and user base for this program, so some issues have taken longer to shake out than others. The following is a list of all these additional PyMailGUI enhancements discovered and applied after the book was published, for completeness; their write-ups are located elsewhere on this page:

1 Feb-01-11 Using POP and SMPT timeout parameters (patched in 1.2, and book) write-up
2 Jan-10-11 Closing temporary output files for HTML-only emails (patched in 1.2, and book) write-up
3 Aug-08-11 Decoding and encoding non-ASCII attachment filenames (patched in 1.3, and book) write-up
4 Oct-01-11 Improved sent-time display in list windows (patched in 1.3) write-up
5 Sep-29-11 Delete and Save timing issue, rare bug (patched in 1.3) write-up
6 Jul-29-11 Using authenticating SMTP servers for sends in mailconfig (patched in 1.3) write-up

Interestingly, two of these changes, #1 and #3, are also inherited by the less functional PyMailCGI webmail example of Chapter 16, because they were applied in the common mailtools package. There were a handful of additional changes made in the examples package and their book listings (e.g., a focus fix in the PyEdit component used by PyMailGUI); see the change log as well as the changes' write-ups on this page for more details.

Screenshots

To sample the effect of changes #3 and #4 above, see the following PyMailGUI screenshots:

The support for non-ASCII attachment filenames and local-relative time in these is new in the 1.3 example package, but the rest is original behavior. See the book for more on PyMailGUI's i18n and Unicode support in other headers and mail content.

Update: New Examples Release 1.3

[Oct-19-11] I've posted a new release of the book examples package, version 1.3, which has patches for all 6 of the PyMailGUI updates listed in this section above. The first two of these were already patched in release 1.2, but the rest are new in 1.3. Get the change log and the complete new examples zip file at O'Reilly's site, or fetch just the files changed within it in this zip file. See the book for details on running PyMailGUI in the examples package (via auto launchers, command lines, etc.). I don't distribute this program standalone, partly because it uses many other files in the book examples tree, and partly because the book is its documentation (but see the later update ahead).

One admin note: Some of the changes made in version 1.3 of the examples package are too large to find their way into reprints of the book itself, but I recommend using the new version in general, and studying the files changed to see what was involved; it's a fair example of code maintenance in action. For changes too big to merge into the book, versions of the changed source files which mirror the code in the book are retained in the examples package with a "BOOK-" name prefix. For details, see the change log which is also file changes\CHANGES.txt in the examples package.

Update: Patch for Running on Python 3.3

[Sep-15-13] There is a simple patch for an address-display issue introduced by a change in Python 3.3's email package, that is included in version 1.4 of the examples package. For details, see the bug, as well as its fix.

Update: PyMailGUI (and PyEdit) Standalone Release

[2018] PyMailGUI eventually was released as a standalone product (apart from the book) in 2017, with numerous enhancements not noted here, and ports to Linux and Mac OS. You can read a summary of all its post-publication changes here, and trace its evolution at its home page and user guide. The related PyEdit program was similarly upgraded, ported, and packaged at the same time; it's post-publication changes history is chronicled here. Book readers are encouraged to begin by studying the base versions of these programs in the book, and move on to explore the new standalone versions' code later. The newer versions are more polished for general use and portability, but retain the original versions' core ideas.


Python 3.2.0 Breaks Scripts Using input() on Windows (LP4E)

[Jan-4-12] If a book example which uses the input() built-in seems to be failing, and you are using Python 3.2.0 in a Windows console window, see this post on Learning Python 4E's update pages.

This built-in was apparently broken temporarily in 3.2.0 (3.2) in Windows console mode, but has been fixed in later Python releases. The quickest fix is to upgrade to 3.2.1 or later, or try a different environment; the book examples work fine in all other Pythons and most other contexts such as IDLE. Scripts in both books may be impacted by this regression.

[Back to Index]


Python 3.2 Removes struct.pack Functionality for str (LP4E)

[Jan-11-12] Another cross-post from the Learning Python update pages about a Python change which impacts examples in Programming Python too—see this note for details on Python 3.2's decision to drop support of str strings for the "s" type code in struct.pack.

This impacts a variety of examples in this book. The simplest fix is to manually encode str Unicode strings to bytes byte strings when passing to struct.pack, per the referenced note. You can also run these examples in 3.1 or earlier if that's an option, though newer Pythons are generally better Pythons.

[Back to Index]


Python 3.3, and Its Impacts on Book Examples

Short story: this section summarizes changes in Python 3.3, and relates them to the book's content. As usual, code that aims to illustrate the bleeding edge is generally among its first casualties.

An Overview of Python 3.3

[Oct-2012] I've started testing the book's examples under Python 3.3, the latest release which features:

Plus more changes I won't list or repeat here. See my earlier 3.3 preview, on the Learning Python update pages, as well as the official 3.3 What's New document at python.org for additional details on 3.3 changes.

More on the New Windows Launcher: Off Page

Of these, the last 3.3 enhancement listed above will probably have the broadest impact (in fact, it affects every Python 3.3+ user on Windows, which, for better or worse, is a huge audience), and merits a few more words. Those words have grown too large for this page, however, so I've moved them to this separate article:

The New Windows Launcher in Python 3.3

The very short story on the launcher is that it registers new executables which are installed on your system path normally; attempts to parse #! Unix-style lines at the top of scripts to determine which version of Python run; and supports command-line arguments that give Python version numbers. The net effect is to better support multiple Pythons coexisting on the same machine, by allowing Python version numbers to be specified on both a per-file and per-command-line basis, and in both full and partial form. It's quite a useful trick, though not without the pitfalls described below. For much more on the launcher in general, see the link above, or the new appendix on the subject in 2013's Learning Python, 5th Edition.

Python 3.3's Impacts on Book Examples

PP4E's book examples were initially developed on 3.1, but tested successfully on 3.2 alpha before publication. In general, most examples tested so far appear to work well on 3.3 and as shown in the book. As expected, though, the evolution in the 3.X line has impacted some behaviors. Among the most notable 3.3 changes that affect book examples:

More here on 3.3 in general as testing continues. You can also read about earlier Python 3.2 changes here, and later 3.4+ changes here.

[Back to Index]


Running PIL Examples on Python 3.2 and Later: Pillow

Short story: PIL became the largely compatible Pillow, which is still actively supported, and freely available at the standard PyPI website here. Fetch and install the Pillow drop-in replacement to run the book's image-related PIL examples, per this section's updates. As of Tk 8.6, this install isn't required if you just need to display PNG images in tkinter GUIs.

The Issue

[Apr-21-12] This book uses the PIL (Python Imaging Library) extension for some image-based examples, both to render thumbnail images, and to display additional image file types in tkinter GUIs. Because PIL was not yet ported to 3.X, the book employed a custom installer provided by PIL's creator, and included this installer in its examples package as a temporary measure pending an official 3.X port.

A reader wrote recently to note that the PIL installer in the book's examples package works only under Python 3.1, and not for 3.2. I don't track PIL's progress, but it has much more utility than the book leverages, and I suspect that this has held up the 3.X port (naturally, this is a non-issue for 2.X readers, for which PIL installers are available). Since this is a general issue which other readers have asked about too, the relevant portion of my reply follows:

About a PIL installer for 3.2: an official 3.X PIL port has 
yet to materialize; it was considered imminent two years ago.
The stop-gap installer I was given by PIL's creator and shipped
in the book examples package is an executable for 3.1 only, 
which I unfortunately have no way to update.

I recommend contacting PIL's creator, F. Lundh, about
this, and/or browsing the archives of and posting your query 
to PIL's email list to see what may be possible today.  

PIL's creator's last known email address (two years ago):

    (please search pythonware.com)

and the image-sig email list for PIL lives here:
 
    http://mail.python.org/mailman/listinfo/image-sig

If you get a resolution on this and can spare the time, I'd
appreciate a copy on what you find; other readers have run 
into the same issue.  If I'm able to uncover anything myself,
I'll follow-up. 

In the worst case, you can always install 3.1 alongside 3.2 
to experiment with PIL examples, or take the examples' code 
as demonstrative if not runnable. 

The Interim

Update, May 2012 A web search turns up unofficial PIL installers for Python 3.2 and 3.3, including those at this site, though I have yet to test their operation with book examples.

Update, July 2012 It's now been verified that the "unofficial" PIL ports for Python 3.X described in the prior update do work correctly, at least on Windows under Python 3.2 and 3.3 and for the PIL subset used by the book's examples—tkinter image display, thumbnail generation, and resize operations. Specifically: