This page is where I collect errata, updates, and general notes about this book. I label items below with the date that they were added to this list, and order by date. Because I have been applying updates in batches to examples release packages, most of these notes are grouped by package release number here. In general, items added on or before an examples package release date have been fixed in that release. For more details, be sure to also see O'Reilly's catalog page, where an additional list of user-reported errata is maintained. Contents here:
Updated the examples distribution package on O'Reilly's site for the following changes:
I've updated the examples distribution package on O'Reilly's site. There are now two versions/files - a zip archive, and a tar/gzip archive. That former is a ".zip" file, and the latter now has a ".tgz" filename extension to avoid renaming issues (Internet Explorer can mangle extensions on downloads: it renames a ".tar.gz" to ".tar.tar"). I've also made a few example updates in this release:
The book examples distribution package is now available for download, at http://examples.oreilly.com/python3/. We're making the examples available on-line in this edition of the book, to allow for updates. A handful of patches were applied to the code in this release; for details, see the package's "UPDATES.txt" file or the items described later on this page.
Note that you can download over HTTP by visiting the web site listed above, or by anonymous FTP to ftp.oreilly.com fetching file examples/python3/PP3E-Examples-1.0.tar.gz in binary mode. Downloading by FTP may be quicker than the web site in some cases.
The auto-launch scripts at the top of the book's examples directory tree (those that begin with the word "Launch_") may fail on Windows when the directory path leading to the examples tree on your computer contains spaces. For example, I recently copied the package to a directory on a new "C:' drive that contained "...\Local Disk\..." as one of its components; this doesn't work, because the command-line used to start the script includes the embedded space, which Windows can't handle unless the path is quoted.
The quick fix for this is to simply move the examples tree to a location on your computer that won't include a space character anywhere in its directory path name. A more robust fix is to add code to the Launcher.py script which automatically adds double-quotes around the directory paths used in command-lines to be launched, prossibly in runCommandLine(); an exercise for the reader.
I am in the process of testing the examples under Python 2.6, the newest and latest version released earlier this month. So far, all the major GUI-based examples run fine under 2.6, unchanged. Python 2.6 is backward compatible with 2.5, the version this book is based upon, so I don't foresee many issues for people who continue to use the 2.X Python line (and most current Python users probably will, for some time to come). More details will be posted here if any problems do pop up.
Note that most of the examples will likely fail under Python 3.0, because of its backward incompatabilities. The fact that the print statament becomes a function in 3.0 is, by itself, enough to guarantee wide book example breakages. Once 3.0 final is officially released, you may be able to get most of the book's code to work by simply running it through the "2to3" code conversion script that will ship with 3.0. More details on this as well, as they emerge. Also see the book "Learning Python 3rd Edition" for notes on Python 3.0 changes, both in the Preface, and scattered thoughout the text.
My ISP recently switched over to authenticated SMTP for sending new emails. This is generally good, because requiring a login allows me to use the book's PyMailGUI example to send mails from any machine with an installed Python; the initial server connection point is irrelevent. Moreover, the example is already instrumented to handle authenticated SMTP automatically -- I simply needeed to change my server details in the PyMailGUI mailconfig.py file to look like this (this varies per account, and note that the POP and SMTP user names differ on my server):
popservername = 'pop.rmi.net' popusername = 'lutz' smtpservername = 'smtpauth.earthlink.net' smtpuser = 'lutz@rmi.net' # require login (None=no login) smtppasswdfile = '' # ask for pswd in gui myaddress = 'lutz@rmi.net' mysignature = 'Thanks,\n--Mark Lutz'
Now, when a mail is sent, PyMailGUI issues a pop-up dialog to input the SMTP password, unless you place it in a local text file whose name is listed in smtppasswdfile. Unfortunatelty, as currently coded, PyailGUI will popup the password dialog on every send, rather than just the first. The reason is a bit subtle, and see the code for more details; but in short, the previously input SMTP password is attached to the write window, not the longer-lived main list window. Because each new message is a new write window object, the password starts empty in each, and must be input anew for each new sent mail.
Note that this is only an issue when using SMTP email servers that require authentication. In fact, the code that supports this feature was never tested until my ISP recently started requiring this. The authentication logic does work properly, so this is more of a note than a fix. The repeated password input can be a bit of an annoyance, though.
I'll leave a patch for this as suggested exercise (or post one later as time allows); probably, a global in the shared names module is a simple fix. Barring that, you can avoid having to enter the SMTP password on each send, by storing the password in a local text file noted in mailconfig.py, like I did on my machine:
smtppasswdfile = 'C:\\Mark\\smtp-pswd.txt' # don't ask in guiThe downside of this, of course, is that you must store your password in a readable file on a possibly public machine (probably not an issue on your own computer).
Speaking of PyMailGui, I regularly check multiple email accounts, and it's fairly inconvenient to have to edit the mailconfig.py file to switch accounts. Ideally, this should be handled in the GUI -- for instance, keep a dictionary of account details objects in mailconfg, and select one on startup via a popup list. As a quick hack, I changed my mailconfig.py to pick an account at import time instead, when PyMailGui.py is run directly (in the following, the path hack is needed when this is run without the book's Launcher self-config logic or manual PYTHONPATH settings, and the try is needed to avoid the EOFError when this is run without a console window for stdin--the case when clicking the PyGadgets auto-launcher script):
import sys, os sys.path.append(os.getcwd() + '\..\..\..\..') # if run without path config myaccounts = ['lutz', 'python-training', 'pp3e'] # first in list is default for account in myaccounts: try: chosen = raw_input('Use account %r?' % account) == 'y' except: chosen = True # EOF if no stdin console if chosen: pickacct = account break else: pickacct = myaccounts[0] if pickacct == 'lutz': popservername = 'pop.rmi.net' popusername = 'lutz' smtpservername = 'smtpauth.earthlink.net' smtpuser = 'lutz@rmi.net' # require login smtppasswdfile = 'C:\\Mark\\smtp-pswd.txt' # don't ask in gui myaddress = 'lutz@rmi.net' mysignature = 'Thanks,\n--Mark Lutz' elif pickacct == 'python-training': popservername = 'pop.earthlink.net' popusername = 'python-training' smtpservername = 'smtpauth.earthlink.net' smtpuser = 'python-training@earthlink.net' # require login smtppasswdfile = '' # ask in gui myaddress = 'python-training@earthlink.net' mysignature = 'Thanks,\n--Python Training' else: popservername = 'pop.earthlink.net' popusername = 'pp3e' smtpservername = 'smtpauth.earthlink.net' smtpuser = 'pp3e@earthlink.net' # require login smtppasswdfile = '' # ask in gui myaddress = 'pp3e@earthlink.net' mysignature = 'Thanks,\n--PP3E Author'
Multiple accounts may need a few additional tweaks as well. For instance, the main window title could display the account user name along with the current server name (see the bottom of PyMailGui2.py for pointers). As one step, I also augment the name of the sent-mail save file so that there will be one per account I send from -- in mailconfig.py, about half way down, insert the account's user name in the sent file name:
sentmailfile = os.path.join(mysourcedir, 'sentmail-%s.txt' % popusername)
Finally, I drag PyMailGui2.py out to a shortcut on my desktop from where I launch one window per email account, and use it to avoid those ridiculous dancing real estate agent ads on my ISP's webmail pages!
In the examples release, four other files besides threadtools.py (mentioned below) had non-ASCII characters from cut-and-paste operations. These are now treated as syntax errors as of Python 2.5, and so were fixed in release 1.2 of the examples tree. They are not an issue in the book itself. See the 1.2 release details above for more information. (In retrospect, one web example may have failed because of this issue, rather than the GET/POST transmission scheme outlined below.)
In addition to textEditor.py (described below), a few other files in the examples tree also had old "PP2E" references. Only one was significant -- a popup window title in the PyDemos2 launcher. Others were either in extra supplemental examples not shown in the book, or correctly use "PP3E" in the book but not in the examples tree. All were repaired in the 1.2 examples release. See the 1.2 release details above for more information.
On Linux, the pack() method used to lay out mail headers at the top of PyMailGUI View windows seems to get skewed under Linux, because of the very different font sizes. The From/To/etc. labels don't align with the corresponding display fields, because they are packed into a separate Frame. Using the grid() method makes for a more platform-neutral appearance.
This isn't quite a bug and doesn't merit a new PyMailGUI version, but grid() does provide a more regular layout for this kind of form. Even on Windows, there can be a very slight skewing of the labels in Write windows with pack(). This example was changed to use grid() in examples release 1.2, though it will still use pack() in the book itself. See file ViewWindows.py in PyMailGUI2 for details; the original pack() version code is still present, but commented-out.
In the book examples distribution package, there apparently is a non-ASCII character on line 9 of file threadtools.py, in the PP3E/GUI/Tools directory. Unfortunately, this causes this file, as well as its PyMailGUI client, to fail under Python 2.5 as is. This is due to a change in Python itself; the examples in question work fine with 2.4. It isn't an issue in the book itself, but will be repaired in the next examples package version.
The character probably came from cutting and pasting the code from the book's Word doc file, and is not a problem under Python 2.4. However, Python 2.5 now treats this as an error for some reason (there is a PEP about this change if you want to look into it further). To fix, delete the "-" on line 9 of file threadtools.py, in the line that begins with "# same time - each kind". It's not impossible that other non-ASCII characters may exist in other files (TBD).
Update: this was fixed in examples release 1.2, November '06 (described above).
Page 413, example 8-24, "gui7.py': There is a superfluous extra ")" in the header of the "message" method, of unknown origins. At "))" in the 5th line down on this page, delete the second ")". This was fixed in the examples distribution package (version 1.1), but not in the book.
Page 63, example 2-27, customizegui.py: The "from Tkinter import *" line at the very top of this example is missing in the book (the result of an unfortunate cut and paste, apparently). Without it, the "mainloop()" call at the end is undefined. This was fixed in the examples distribution package (version 1.1), but not in the book.
As described ahead, Internet Explorer may have issues when using POST to submit data to CGI scripts, using the web server in the book. This is an issue only with the combination of the POST transmission method, the IE web browser, and the simple server used in the book. To avoid the issue, most of the HTML forms have been changed to use GET instead of POST in the examples distribution package (version 1.1), though not in the book itself. Exception: the putfile.html upload form still requires POST (see page 1054 in the text for details). The PyMailCGI email edit form must use POST for attachments too, for the same reasons.
Curiously, both the putfile and PyMailCGI examples work fine with POST, under the book's web server and the IE browser; their "enctype" attribute apparently matters in this context, but it's unclear why. Another finding: under Python 2.5, it appears the webserver used in the book has occaional issues with GET and the Firefox web browser; this seems fairly bizarre, and I have no time to uncover why. Try changing between GET and POST if the examples don't work for you, or use a more robust web server such as Apache.
Page 1010, example 16-15: There seems to be an extra and superfluous "<form>" tag in this HTML file; you may have to delete one of the two to make this example work. This was fixed in the examples distribution package, but not in the book.
PyEdit, example 12-3 on page 646, has a legacy import of the form "from PP2E.Gui.Tools..." which must be "from PP3E.Gui.Tools..." in order to run. This was fixed in the examples distribution, but not in the book. It reflects the fact that the examples were scattered between two directory trees during development of this edition; this reference slipped through the cracks when the trees were merged.
Some CGI examples in preview Chapter 2 and other server-side scripting examples in the Internet part may not work as is with Internet Explorer and the book's webserver script. Internet Explorer appears to have problems with "POST" form actions, when talking to the Python coded locally running webserver.py script used in the book. To make them work under IE and this server, you may have to change the HTML file's form "action" to be "GET" instead of "POST". Alternatively, you can use the Firefox web browser which was used for testing, and which handles all the examples correctly, or run a different web server such as Apache. Action tags were changed to "GET" in the Preview directory of the examples distribution, but nowhere else. (Also see the Oct 5 update above: most examples now use GET.)
See the Oct '08 note earlier on this page for comments about using the book and its examples with the new Python 2.6 and 3.0 releases. The short story is that 2.6 is fully compatible and so should be fine, but 3.0 may require a code conversion script to be run before some book examples will work.
These are not program errors and were not patched in the examples tree, but four examples tree usage notes are worth mentioning here.
The header [So What's "Python: The Sequel"?] was not supposed to have any quotes in it (they were added in the edit process). It should be [So What's Python: The Sequel] as it was in the prior edition. I'm probably being picky here, but the quotes modify the original meaning of this enough to mention; it's a backreference to a sidebar in the preface of the same title.
Some GUI examples will not run without an icon file present (e.g., toplevel2.py, tkinter103.py). To make them run, icon files have been added to the examples distribution package (version 1.1). However, note that the examples in question assume that a Windows style ".ico" icon file is being employed; on other platforms, you may have still to adjust the icon file name both in the scripts and externally. Larger examples that use custom icons should generally work as is on non-Windows platforms, but may not display an icon.
The book makes reference to some text-based circle plotting scripts when discussing the PyClock example; these were added back to the examples distribution package (version 1.1).
PyCalc, example 21-6 on page 1390, has a comment near the top about using windows.py to get a window icon. In the end, this change was not made tio this code. This comment was removed in the examples distribution, but not in the book.
A few example's file labels are slightly off, though the files' true locations are usually implied by the text or usage examples. Examples 19-25 through 19-28 are actually in the TableBrowser subdirectory of PyForm; Example 18-19 is really file comserver-test-vbs.html; and in Chapter 17, all the imported ".py" module files in PyMailCGI are actually stored in the PyMailCgi\cgi-bin subdirectory along with the CGI scripts, as described in the text. The latter will work either way on Windows with the server used in the book, but placing modules in the cgi-bin directory make imports from CGI scripts work more portably; on other platforms that spawn scripts, cgi-bin will be the current working directory for imports. All file locations are correct in the examples distribution.
The XML parsing coverage shows up in the Internet section in this edition; in retrospect, it should probably have been referenced from the text processing chapter as well. XML processing is not necessarily tied to Internet scripting alone.
There are a few places in the text where the file ".readlines()" method is called in "for" loops. These are legacy code. In general, it's better practice today to omit the ".readlines()" part, and rely on file iterators, as discussed in Chapter 4, page 146. This is true for both normal files, as well as file objects returned by the "os.popen" shell command spawner. File iterators save space in general, because the entire file is not loaded into memory all at once. They are even more important for "os.popen" because the file iterator will allow your script to be interleaved in time with the spawned command, but ".readlines()" will block until the command generates all its output and exits.
Note that there are now two directories of database-related code in the examples distribution: "Database" is for SQL and ZODB database examples which require 3rd-party extensions, and "Dbase" contains examples that use Python standard library tools such as pickle and shelve.
In Chapter 20, page 1304, a type subclassing example appears without a filename label. In the examples distribution, this code is in file typesubclasses.py. The following example has no label either, but its use case implies that it is in typesubclass.py. Also note that in the first release of the examples distribution, typesubclasses.py's self-test code appears twice due to a bad cut-and-paste; it simply generates duplicate outputs (update: this was fixed in version 1.1 of the examples package.)
The extension for LaunchBrowser (Example 6-15) is .pyw in the examples distribuion, not a .py as shown in the book. Also, in PyDemos2, I added a few related files to the code list of PyInternet, and one related file to PyForm's list (additional source files pop up).
The image files shown for the PyPhoto and email attachment examples in the book were reduced in the examples distribution package to save space. Use your own photos to experiment further with these tools.
The original wording in this pararaph was mangled somewhere between the QC1 and QC2 phases of the edit process. The sentence:
"And although Python is dynamically typed -- types are tracked automatically instead of being declared (it is still strongly typed) -- every operation is sanity checked as your program runs."
Was original written as:
"And although Python is dynamically typed -- types are tracked automatically instead of being declared, it is still strongly typed -- every operation is sanity checked as your program runs."
The modified version works in a way, but is difficult to parse, and subtly different enough from its original intent to be broken. Technical writing can be a very tricky affair.