GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||||||||||||||
GeezerVison is showing learning-python.com — 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 ResourcesFor 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 HereGeneral Book Notes
Example-Specific Notes
Python Changes Since Publication
Supplemental Examples
Book CorrectionsMore 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 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 .../PP4E/Internet/Email/PyMailGui/altconfigs/launch_PyMailGui.pychange 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 meYou 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 Python Email Package Surrogates Bug in 3.3.3, Fixed in 3.3.4
Short story:
due to a temporary regression in Python's The Regression in 3.3.3
[Mar-4-14]
In 3.3.3 only, Python's 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
Timing: because the error occurs on Send in the The Repair in 3.3.4The 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 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 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 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 More PyMailGUI IdeasFrom 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
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
To apply and use the patch for this Python change, simply fetch the following two files,
and copy them to 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: [email protected] > > 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:[email protected]] > 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' PyMailGUI: Enhancements Summary, ScreenshotsShort 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:
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 ScreenshotsTo 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 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 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 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. 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
This impacts a variety of examples in this book. The simplest fix is to manually
encode Python 3.3, and Its Impacts on Book ExamplesShort 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:
More on the New Windows Launcher: Off PageOf 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 Python 3.3's Impacts on Book ExamplesPP4E'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. 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 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 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 InterimUpdate, 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:
The Resolution
Update, May 2013 It looks like the PIL ports at the site described above are now an official fork named Pillow, and are now also available atthe PyPI site. Despite the name and
location changes, this package is still imported as module One nit on compatibility—to use Pillow instead of PIL, you must change any: import Imageto this: from PIL import Imagebecause of the way Pillow structures its namespaces. After this, Pillow works the same as the former PIL (and as it's documented in the book), but bear in mind that additional changes and deprecations have arisen over in Pillow time (e.g., Python 2.X is not supported by its latest releases). For current status, read the summary of Pillow's morph here, and browse its full docs here.
It's also worth noting that Tk 8.6 (included with python.org's
Python installers for Windows since 3.4, and currently bundled with its Mac OS installers) can display
PNG images in More on pickle Module Constraints: Bound Methods (LP4E)[Oct-15-11] I posted a note about pickling and bound methods on the clarifications page of the book Learning Python 4th Edition which provides some additional background on how and why bound methods cannot be pickled.
Since that note also pertains to the coverage of pickling in this book—in
Chapter 1's quick tour, Chapter 5's More on Printing Non-ASCII Filenames: PYTHONIOENCODING
Short story: Be sure to set your The Issue
[Oct-28-11]
On pages 279-282, the book discusses in substantial depth how
Filename Print Failures
As an illustrative example, I recently noticed a print failure
in the c:\...\PP4E\System\Filetools>diffall.py e: C:\SD-card-xfer-oct2711 > temp
Traceback (most recent call last):
File "C:\...\PP4E\System\Filetools\diffall.py", line 80, in <module>
comparetrees(dir1, dir2, diffs, True) # changes diffs in-place
File "C:\...\PP4E\System\Filetools\diffall.py", line 69, in comparetrees
comparetrees(path1, path2, diffs, verbose)
...
File "C:\...\PP4E\System\Filetools\diffall.py", line 56, in comparetrees
if verbose: print(name, 'matches')
File "C:\Python31\lib\encodings\cp1252.py", line 19, in encode
return codecs.charmap_encode(input,self.errors,encoding_table)[0]
UnicodeEncodeError: 'charmap' codec can't encode characters in position 0-6: character maps to <undefined>
The end of the -------------------- Comparing e:Books\4E\PP4E\examples-official\1.3\unpacked\PP4E-Examples-1.3\changes\detailed-diffs\1.3\patched-files-13\i18n-filenames-tests to [...] Directory lists are identical Comparing contents Mail-saved-after-sent--OpenMeInGUI.txt matches Fix 1: Setting PYTHONIOENCODING
Now, as suggested in the book's footnote on page 282, this script works as
is without errors if you simply change your c:\...\PP4E\System\Filetools>set PYTHONIOENCODING=utf-8 c:\...\PP4E\System\Filetools>diffall.py e: C:\SD-card-xfer-oct2711 > temp c:\...\PP4E\System\Filetools>notepad temp Here is part of the temp output file, at the place where the prints failed before the environment setting: -------------------- Comparing e:Books\4E\PP4E\examples-official\1.3\unpacked\PP4E-Examples-1.3\changes\detailed-diffs\1.3\patched-files-13\i18n-filenames-tests to [...] Directory lists are identical Comparing contents Mail-saved-after-sent--OpenMeInGUI.txt matches Поворот IMG_1412.txt matches 从~技~术~走~向~管~理.xls matches 金牌销售2天一夜实战训练.xls matches -------------------- Fix 2: Catching Encoding Exceptions
Alternatively, it might be a bit more robust and convenient in some scenarios
to catch the exception in the script itself and print as raw bytes, instead of
printing Unicode text that must be encodable per the print setting. A modified
version of this script that does this and works without environment setting
changes is available here: diffall-SAFE.py.
Here are the parts added and modified in def tryprint(*args):
"""
Added Oct-27-11, post publication and post examples 1.3:
Don't fail with an exception for unprintable filenames;
See pages 279-282, and the similar tryprint on page 276;
Started failing for non-ASCII filenames in email test dirs;
In general, any filename printers in 3.X may require this,
unless PYTHONIOENCODING is set as needed (e.g., to utf-8);
"""
try:
print(*args) # filenames might fail to encode
except UnicodeEncodeError:
print('--UNPRINTABLE FILE NAME--', *(arg.encode() for arg in args))
def comparetrees(dir1, dir2, diffs, verbose=False):
...
if (not bytes1) and (not bytes2):
if verbose: tryprint(name, 'matches')
...
if bytes1 != bytes2:
diffs.append('files differ at %s - %s' % (path1, path2))
tryprint(name, 'DIFFERS')
...
for name in missed:
diffs.append('files missed at %s - %s: %s' % (dir1, dir2, name))
tryprint(name, 'DIFFERS')
if __name__ == '__main__':
...
for diff in diffs: tryprint('-', diff)
This changed script still makes some assumptions (it must be able to encode the filename per the platform default, which is UTF-8 on Windows) and may need further honing on some platforms. When run, though, it avoids print failures explicitly; here's what it does with non-ASCII filenames in the printed output in the temp file: -------------------- Comparing e:Books\4E\PP4E\examples-official\1.3\unpacked\PP4E-Examples-1.3\changes\detailed-diffs\1.3\patched-files-13\i18n-filenames-tests to [...] Directory lists are identical Comparing contents Mail-saved-after-sent--OpenMeInGUI.txt matches --UNPRINTABLE FILE NAME-- b'\xd0\x9f\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd0\xbe\xd1\x82 IMG_1412.txt' b'matches' --UNPRINTABLE FILE NAME-- b'\xe4\xbb\x8e~\xe6\x8a\x80~\xe6\x9c\xaf~\xe8\xb5\xb0~\xe5\x90\x91~\xe7\xae\xa1~\xe7\x90\x86.xls' b'matches' --UNPRINTABLE FILE NAME-- b'\xe9\x87\x91\xe7\x89\x8c\xe9\x94\x80\xe5\x94\xae2\xe5\xa4\xa9\xe4\xb8\x80\xe5\xa4\x9c\xe5\xae\x9e[...]\x83.xls' b'matches' --------------------
This works, but it many cases it might be simpler and will require
much less code to set your
I'm not going to mark this for changing in reprints or new example
releases, partly because this is a general issue which is already
well documented in the book; partly because this is not the only
book example that takes a loose approach to printing filenames;
and mostly because such scripts will work without changes if you set
your Update: New Stream Defaults, ascii(), Mac OS
[2017]
As a postscript, the most recent Pythons have changed the default output
stream encodings to use UTF-8 on Windows, so you may not need to set your
Additionally, the built-in It's also worth noting that this issue seems most grievous on Windows. Mac OS, for example, happily and naturally supports Unicode output in its Terminal app, no environment changes required. But the world keeps using Windows anyhow...
Bonus Example: Website Admin, with HTML and URL Parsing, FTPcleansite is a book-related example originally posted here in 2010 and updated in 2014. It recursively walks a website's links to locate unused files, by parsing the HTML files accessible from one or more root pages, and noting the files of any type they reference. Its goal is to help locate unused files that may be removed, while leveraging multiple topics covered in the book. Latest Version: Broader Usage Roles
[Feb-19-14]
The latest version of this script, 1.1, is available in this zipfile:
The zipfile also has new example run logs, and updated versions of the book's These scripts were used to purge old, unreferenced files from my websites—some now nearly two decades old—by adding pages to ignore until old material was discarded as desired. For the target site, cleansite caught 115 unused files among 317 total, and shaved 3G off its 10G total size. You may need to augment this with multiple-file searches (see the Grep tool in the book's PyEdit GUI), and this is still a bit user-specific, but serves its purpose for my use cases. Original Version and Description[Dec-28-10] As a sort of reward for stumbling onto this page, I've uploaded an extra example script here which would have appeared with the book's HTML parsing coverage in Chapter 19, had this book project enjoyed unlimited time and space. This script uses Python's HTML and URL parsing tools to try to isolate all the unused files in a website's directory. I use this script for my training website, as well as my book support site (the latter after fixing some HTML errors that rendered the script inaccurate when Python's strict HTML parser failed and caused some used files to be missed). This script also includes code to delete the unused files from a remote site by FTP if you wish to enable it (pending a resolution on the parser failures issue), and includes suggestions for parsing with pattern matching instead of the HTML parser.
Download: The script itself lives here: Bonus Example: Book lottery, with POP, SMTP, email, and CGIpylotto is a book-related script used to give away books to randomly selected students in some of the live classes I teach (sorry, its lotteries are not open to the web at large!). It ties together a number of the book's topics and techniques, and has been posted here in both original and updated forms.Latest Version: More Usage Modes[Feb-22-11] In light of security constraints in a recent class, I've completely rewritten the pylotto script for worst-case scenarios. It can now select from both emails, and a names file created manually or via web form submits, and can be run in both console and remote CGI modes. In pathological cases, it can be run locally to select from a local names file—the need for which was underscored by a recent class somewhere in the wilds of California. I've also updated to port the single script to work on both Python 3.X and 2.X, and to properly escape student names in the reply HTML. Here's the new version's code—use the "view source" option to view the form's HTML:
lotto-howto-email.txt and
lotto-howto-web.txt,
as well as a last-resort script which became a class exercise and
gave rise to (and is subsumed by) this new generalized
Pylotto: simple-pylotto.py.
The rest of this section describes the original, now defunct version, but also gives the back story. The new version has the same goals, but supports web form and local file sign-up modes in addition to emails. Original Version and Description[Jan-11-11] Here's another supplemental example that might have appeared in the book, if not for time and its conceptual dependencies. I wrote this script, pylotto, in order to give away free books in some of the classes I teach. O'Reilly always sends a batch of free copies to authors, and if I kept a dozen copies of every one of the 12 Python books I've written, some of which are not exactly small, I'd probably need a bigger house. To enter the book lottery, students send an email message to the book's account, with "PYLOTTO" in the subject line. At the end of the class, the script scans, parses, and deletes these emails, and selects a set of their "From" addresses at random as winners. It's not Vegas, but it's fair, and serves as a nice example of practical Python programming that ties together a number of tools presented in the book. This script also has a test mode that sends test emails, and an as-CGI mode for running on a Web server if the training site doesn't allow POP email access or SSH (many don't).
Download: Fetch the script here:
New: See also Naturally, I don't give away books in every class I teach (this basically depends on how many freebies O'Reilly has given to me, and how willing I am to lug around a big, giant book in my checked luggage). Even so, scripts such as this one and others in the book which address real, practical needs can go far to help illustrate Python applications in action once students or readers have mastered Python language fundamentals. As stated in the book, Python tends to become a sort of enabling technology for most people who've learned to use it well. Bonus Example: Extracting Music Files from an iTunes Folder Treeflatten-itunes is a book-related example that copies all music files in a folder tree to a single, flat folder for easier access and transfer, and puts some of the book's topics to work on a realistic task. It's been released here in both initial and revised forms. For reference, this section references the following code:
Latest Version: Resolving Disparate Collections
[Nov-5-11]
I've written a new and very different version of this script to be used
to isolate differences in iTunes collections on different laptops or
archives, rather than just flatten directories and detect protected files.
Grab the new 2.X/3.X version here: I wrote this version to help resolve differences between iTunes collections on multiple machines that have fallen out of sync over time. It's easy to get in this state if you buy songs on whatever laptop you have at the moment and don't synchronize religiously (cloud storage addresses this in theory, though not without potential downsides of its own). Because iTunes may accumulate different files and directory structures on different machines, it's nearly impossible to synchronize unless you normalize its files into a simpler, uniform structure.
This new version addresses this by sorting all music files in an entire directory
tree into 4 flat directories (playable, protected, irrelevant, and other),
for each collection it is run against. This makes it simpler both to run later
comparisons to spot differences (e.g., using the book's
After collecting files into flat directories with this script, I later merge
the playable files directories with manual drag-and-drop operations, and also
run a simpler script, Note: this is only an iTunes (or other music library) utility, for analyzing your collections' content or moving your music files. It's not a player or iTunes replacement, and although its result directories retain all iTunes music files, they may not retain all iTunes information. For example, due to the way the script flattens music directory trees, its result directories may lose some associations between music files and their album artwork images, at least for images not embedded in music files themselves (e.g., via ID3v2 frames for MP3 files). Writing a full replacement for iTunes in Python (PyTunes?) would be an interesting project, and others have already made progress along these lines—check out:
Original Version and Description[Feb-3-11] Here's something similarly practical, but a bit simpler than the prior two sections' programs—a Python script which walks all the folders and subfolders in an iTunes directory tree, to copy all music files in the tree to a single flat directory. I use this to create a single directory of all my music on a memory stick, so it can be used conveniently on the harddrive in a vehicle I drive. iTunes seems fond of nested directories, and the player in the vehicle in question doesn't do well in their presence. This example might have appeared in the larger systems examples chapter, if not for time, space, and the fact that it's not too much different from tree-walkers already in that chapter.
Download: Fetch the script here: Related Script: tagpixFor another directory-walker media tool that similarly organizes media content spread across folder trees, see also tagpix, which extracts EXIF metadata tags from photos with PIL, and is referenced elsewhere on this page. Changes in Python 3.2Short story: this section deals with prominent changes in Python 3.2, with a focus on email-processing tools that impact the book's examples.An Overview of Python 3.2[Dec-31-10] As described in its Preface, this book was written under Python 3.1, and its major examples were retested and verified to work under Python 3.2 alpha just before publication. Because of that, this book is technically based on both 3.1 and 3.2, though it addresses the entire 3.X line in general.
That said, you will find some discussion of 3.1 library issues in the book that
have changed or improved in the upcoming 3.2 version, which is due to be released
roughly two months after this book's release date (3.2 final is currently
scheduled for mid-February 2011). Some of the issues in 3.1's
In fact, many or most of the issues of the 3.1 email and bytes in 3.2: the Surrogates Replacement Trick
As a prominent example of
In short, the
On the downside, because this scheme assumes that message data is both decoded to Unicode text
and re-encoded to
Also note that while this change may be a first step towards addressing the related
CGI uploads issue described in Chapters 15 and 16, that issue still exists in Python 3.2.
As described in the book, CGI uploads are somewhat broken in 3.X today because Python's CGI
module uses the
For email, though, 3.2's library fixes represent a significant improvement over 3.1: the
decode-to- Other 3.2 Changes
For more on the Python 3.2 release, including its new
Not covered in that note is the very late 3.2 addition of its
While you're at the Learning Python site, see also its preview of mid-2012's expected Python 3.3.
Update, Mar-2011
After additional research, it's now clear that the 3.2 Update, 2018 Be sure to also see the newer Python Changes 2014+ page for later Python changes not mentioned here. That page covers Pythons 3.4+, but its preamble also has links for Python changes that cropped up between PP4E's publication and 2014 (post LP5E), including the later 3.3 coverage here. Adjusting to Local Time in PyMailGUI List Windows (Patched in 1.3)Short story: the original version of PyMailGUI in the book didn't scale email times to local (display) time, but this was added to the version in the book's examples package early on using coding techniques described here. The Issue[Oct-1-11] As originally coded, message-sent time is not displayed very usefully in PyMailGUI's list windows. The GUI blindly displays the full, raw text of the Date header field. Worse, the time portion of this header is truncated by the display such that the "+NNNN" field which denotes what the sent time really is relative to GMT is not shown. The net effect is that you can't tell in the GUI when a message was sent or which messages were sent before others without looking at the raw text and deciphering the Date time string manually. The GUI lists emails in order received at the POP mail server only. The Fix
To fix, the time in the Date field of list windows should be shown in full, and be shown
relative to either the local time zone or GMT uniformly for all emails received. See
the Python >>> from email.utils import formatdate # in Python 3.2 >>> formatdate() 'Thu, 29 Sep 2011 17:27:53 -0000' # relative to gmt >>> formatdate(localtime=True) 'Thu, 29 Sep 2011 13:27:55 -0400' # relative to local (us eastern, -4 hours) >>> formatdate(usegmt=True) 'Thu, 29 Sep 2011 17:27:59 GMT' # explicit gmt relative for http Applying the corresponding technique for adjusting a received date/time string to the local time zone in PyMailGUI's code is officially delegated to suggested exercise, but the following might help. To convert a GMT-based date/time string to a date/time string in the local US Eastern time zone, try this (it's 5:45 PM GMT and 1:45 PM locally): >>> from email.utils import formatdate >>> from email._parseaddr import parsedate_tz, mktime_tz >>> now = formatdate() # gmt-based => local (eastern) >>> now 'Thu, 29 Sep 2011 17:45:26 -0000' >>> parsedate_tz(now) # time string => time tuple (2011, 9, 29, 17, 45, 26, 0, 1, -1, 0) >>> mktime_tz(parsedate_tz(now)) # time tuple => to utc timestamp 1317318326.0 >>> formatdate(mktime_tz(parsedate_tz(now))) # utc timestamp => time string 'Thu, 29 Sep 2011 17:45:26 -0000' >>> formatdate(mktime_tz(parsedate_tz(now)), localtime=True) 'Thu, 29 Sep 2011 13:45:26 -0400' Using this scheme to convert from local to GMT, or local to local could proceed as follows: >>> here = formatdate(localtime=True) # eastern => gmt or local (eastern) >>> here 'Thu, 29 Sep 2011 13:45:47 -0400' >>> formatdate(mktime_tz(parsedate_tz(here))) 'Thu, 29 Sep 2011 17:45:47 -0000' >>> formatdate(mktime_tz(parsedate_tz(here)), localtime=True) 'Thu, 29 Sep 2011 13:45:47 -0400' And finally, converting a date/time string from the US Pacific time zone to either GMT or the local US Eastern time zone might be done this way (it's now 10:46 AM Pacific, 5:46 PM GMT, and 1:46 Eastern/local): >>> there = 'Thu, 29 Sep 2011 10:46:32 -0700' # pacific => gmt or local (eastern) >>> formatdate(mktime_tz(parsedate_tz(there))) 'Thu, 29 Sep 2011 17:46:32 -0000' >>> formatdate(mktime_tz(parsedate_tz(there)), localtime=True) 'Thu, 29 Sep 2011 13:46:32 -0400'
Update, Oct-19-11
Because the patch was minor, I wound up fixing this in the examples package
after all: see the release description above for more on
version 1.3 of the book examples package in which this fix first appears.
As usual, the fix was propagated to all later PyMailGUIs.
The code edits were too large to add to the book itself, unfortunately,
so fetch the examples package for more details.
Rare Delete and Save Timing Issue in PyMailGUI (Patched in 1.3)Short story: Though unlikely, it's possible that the original PyMailGUI's delete (the GUI's Delete) may delete the wrong message if you request a new delete while one is already running. Either don't do this; read on to see how to fix this potential issue in code yourself; or get the latest book examples package or PyMailGUI release which incorporated fixes for the issue long ago. The Issue
[Sep-29-11]
PyMailGUI's initial version included an obscure timing issue related to delete operations.
As coded in the book, it's not impossible that a deletion thread's exit action may be
allowed to run and clear the delete-in-progress flag, before a new delete request has a
chance to check this flag. This can occur apparently because the new delete's
confirmation dialog popup releases control to the GUI event stream, which can then run
a prior delete's exit action from an
The net result is that a new delete might overlap with one in progress, and incorrectly
delete the wrong POP message numbers made invalid in the GUI by the prior delete—a
scenario the book and code both explicitly state must be avoided. Note that the system
does go to great lengths to compare mail headers so as to ensure that each message being
deleted in the GUI matches the message being deleted on the server once deletions begin,
in case the server's inbox changes before a selected message is deleted (see method
This behavior is timing dependent, rare, and can occur only if you issue a new delete request while one is already in progress, and then only if you're unlucky enough to have the prior request's exit action run exactly after the time you press Delete for the new request and before you're able to click "OK" in the delete confirmation popup. However, this is also a classic and even illustrative timing bug; it reflects both the lack of broader testing for a book's examples, and a misconception of the confirmation dialog's modality—the program assumed this dialog was truly modal (blocking), such that all the code from the start of a new delete callback handler through its delete-in-progress test ran atomically. This must not be case, as I've seen a few incorrect mails deleted when running many deletes in parallel. The FixTo avoid this potential entirely, don't run overlapping delete requests. Better still, fix the code to avoid it in all cases by running the delete-in-progress test immediately in the delete callback handler, and before the confirmation dialog is issued. Because the delete-in-progress test logic differs between the server and file list windows, this can be done by either moving the confirmation dialog call into each subclass's code, or adding a subclass-specific okay-to-delete method called from the superclass delete callback code.
For more details, see Update, Oct-19-11 Given its potential severity, I wound up patching and fixing this issue in version 1.3 of the book examples package. The fix, present in all later PyMailGUIs, prohibits delete overlaps via the code changes described above; see the release description above. There appeared to also be a similar potential for timing issues for Saves due to their file-selection dialog, which was also patched to check for blocking state before the dialog instead of after, though this seemed much less likely or harmful. Regrettably, these fixes were too large to add to the book itself. More on Encoded Email-Attachment Filenames (Patched in 1.3)Short story: this section describes a limitation in the original version of PyMailGUI in the book, which was later lifted in both subsequent releases of the book's examples package, and standalone PyMailGUI packages. Its resolution story told here, though, is illustrative of both Unicode issues and code maintenance at large. The Issue[Aug-8-11] After presenting the PyMailGUI client, Chapter 14 discusses a variety of suggested improvements to this system. Among them, its Unicode enhancements section on page 1123 mentions that the filenames of attached parts might also be in i18N encoded form in some rare cases, and require the same MIME and Unicode decoding steps that are already applied to other primary email headers such as Subject, From, and To. In the book's PyMailGUI the latter of these are properly decoded for display and encoded for sends, but attachment filenames are currently not.
Encoded attachment filenames weren't present in the test cases used to
develop this version of PyMailGUI, so they received only a brief mention
in the improvements list. Moreover, some minor Unicode issues were
intentionally given limited attention, partly because this book's size
and time constraints limit its scope, but also because this edition
uses the Python 3.1 Lately, however, I've noticed that encoded filenames are becoming more common. This doesn't seem like a great feature of email in general—Unicode filenames that are encoded in a way not supported by the receiving platform's filesystem won't work and would have to be renamed automatically (e.g., sending a Russian or Chinese filename may fail when saved on an ASCII-only filesystem). Because of the increasing prevalence of such emails, though, I want to elaborate on ways to address them here. GUI WorkaroundAs is, the only GUI-based way to handle parts with encoded filenames in the client are to save the full enclosing email in a mail save file (list window: select, and Save); edit the mail's text in its save file to rename the attachment file name in its mail header line; and then reopen the mail from its save file (list window: Open save file, select in popup file list window, and View). This works, but obviously isn't a very user-friendly procedure. Coding Fix
To do better, it might be simple to augment the
For the adventurous, the Update: Partial Fix Details
[Aug-15-11]
To help you get started, it appears that the first part of the coding fix,
decoding i18n filenames (but not also testing for their correctness on the
receiving platform), is simply a matter of changing the very last line of the
return (filename, contype)
return (self.decodeHeader(filename), contype) # aug 2011: decode fname
At least per minimal testing so far, this does the trick—Chinese and Russian encoded attachment filenames are properly decoded, just like other encoded text in primary email headers. These decoded filenames also happen to work unchanged on the Windows operating system (per UTF-8) in their decoded forms, though they may not work on some platforms, and their original i18n undecoded string forms always fail as filenames on Windows too and generate error popups in the GUI. For instance, a Russian email's JPEG image attachment whose i18n filename was given in its part headers with a non-ASCII character set ("KOI8-R"), base64 translation ("B"), and the encoded text ("8M/..."): Content-Type: image/jpeg; name="=?KOI8-R?B?8M/Xz9LP1CBJTUdfMTQxMi5KUEc=?=" Content-Disposition: attachment; filename="=?KOI8-R?B?8M/Xz9LP1CBJTUdfMTQxMi5KUA==?= =?KOI8-R?B?Rw==?=" Content-Transfer-Encoding: base64with the patch is now correctly decoded to filename: Поворот IMG_1412.JPG.
The original encoded filename text in the headers does not work as is. Similarly,
a Chinese spam email attachment's headers using UTF-8, base64 encoded values:
Content-Type: application/vnd.ms-excel; name="=?utf-8?B?6YeR54mM6ZSA5ZSuMuWkqeS4gOWknOWunuaImOiuree7gy54bHM=?=" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="=?utf-8?B?6YeR54mM6ZSA5ZSuMuWkqeS4gOWknOWunuaImOiuree7gy54bHM=?="now decodes to filename: 金牌销售2天一夜实战训练.xls (which will look right in this
web page if your browser understands UTF-8 text). With this patch, these decoded
filenames now appear correctly in the GUI's part buttons and its Parts list pop-up,
and when saved to files and opened in other applications. Non-encoded filenames
pass though the decoder unchanged as expected, so this should not break any cases
that worked previously.
Because this is a simple change that doesn't alter line numbers, and because encoded filenames are becoming more common, I may mark this as a future reprints update, but be sure to patch your code copy this way if it does not include the enhancement and you start seeing encoded filenames in emails which you care to view. TBD: Filesystem Limitations, Encoding for Sends Too?
Also keep in mind that the prior section's fix is partial: it still does not address
filenames which won't work on the underlying platform's file system and may need to be
renamed. Perhaps just as glaring, the fix handles decoding for display
of fetched emails only; there is no special logic for encoding non-ASCII attachment
filenames per i18n standards for sends—something which might have to be very
similarly addressed near the end of the basename = os.path.basename(filename)
basename = self.encodeHeader(os.path.basename(filename)) # aug 2011
This should suffice: filenames that encode as ASCII are left intact and others
are encoded per the UTF-8 default, though it would ideally also apply the mailconfig
module's headersEncodeTo setting if present. But I'll leave this in the to-be-tested
column; I don't send such emails, and doing so seems a bit dubious in any event on the portability
grounds mentioned above. In other words, there is still plenty of room for
improvement. Enhance as desired.
The Standard Futurisms Caveat
Ideally, Python's
Update, Oct-19-11
This issue was patched and fixed in full for both sends and receives in release 1.3
of the book examples package, and is no longer present in any later PyMailGUIs.
See the release description which includes
screenshots of the fix,
and the formal patch description below.
This fix was small enough that it will appear in the book itself in a future reprint.
Note that because the fix was applied in common Using SMTP Email Servers with Logins and Ports (Patched in 1.3)Short story: some ISP's email servers allow or require use of ports with password-validated access and SSL/TLS secure transfers. Port numbers are automatically supported in the book's PyMailGUI, and illustrated here; user-configurable SSL/TLS support was added in the standalone release. The Issue[Jul-29-11] As stated in the book, you may need to change your SMTP mail server configurations to use the book's email clients to send email directly. This is especially true when you try to send mail by SMTP on public networks. Some of this is ISP-specific, but here are a few pointers.
This recently resurfaced for me because my email sends stopped working
after my broadband provider changed their network. In short,
they locked down the standard SMTP send port 25 in order to prevent spam,
but this prevented direct sends using the server configurations I had been
using. In the smtpuser = None # per your ISP, None = no login smtppasswdfile = '' # if login, set to '' to be asked smtpservername = 'smtpout.secureserver.net' # if port 25 open for SMTP on networkThis no longer worked after the SMTP port lockdown. To send emails, I had to change my SMTP server details to use an authenticating SMTP server at another third-party ISP, running on a non-standard port number (this server runs on EarthLink, which is different from my broadband provider): smtpuser = '[email protected]' # login, authenticate smtppasswdfile = '' # ask for password in GUI smtpservername = 'smtpauth.hosting.earthlink.net:587' # 3rd party ISP, port 587When so configured, I have to login to my email account at this ISP on the first email send in a session (PyMailGUI pops up a prompt for password input), but Python's smtplib module automatically parses off and converses
over the custom SMTP port number included at the end of the server-name string.
This all just works in both PyMailGUI and smtplib, with no code changes required.
With these authenticated SMTP settings, email sends seem to work on many more networks than before, and I avoid having to resort to webmail with all its annoying advertising. As an alternative, I could have routed email sends through the broadband provider's SMTP server directly, but this scheme can sometimes be tagged as spam, and may require a direct connection to the provider's network which may not always be possible: smtpuser = None # per your ISP smtppasswdfile = '' # set to '' to be asked smtpservername = 'mail.mailmt.com' # your isp or local network's serverSee your ISP for more on your server settings, and the comments in mailconfig.py and the book for more on client configuration settings.
Postscript: I recently had to change servers yet again to use a broadband provider account when EarthLink's SMTP server started timing out—the following works in all contexts now for me, but your mileage will certainly vary (and possibly, very often!): smtpuser = 'myloginname' # nonblank=authenticated smtppasswdfile = '' # ''=ask in GUI once smtpservername = 'smtp.comcast.net:587' Update, Oct-19-11 Per the release description above, there is now a demo of the ideas presented here in release 1.3 (and later) of the book examples package. The changes were too large to add to the book itself.
Update, 2018
There is also more complete support for SSL/TLS secure email servers in PyMailGUI's
later standalone release. Such servers run on
dedicated ports, use password-based authentication, and are now commonly
required by many ISPs. See the latest PyMailGUI's
change log and
Explicitly Close Temporary File in PyMailGUI (Patched in 1.2)Short story: the original version of PyMailGUI in the book omitted a file close call, which on some machines caused HTML viewers to misbehave. This was repaired in version 1.2 of the book's examples, in the text of the book itself, and in all later PyMailGUIs. The Issue
[Jan-10-11]
I recently spotted something unusual in Chapter 14's PyMailGUI, in module
This isn't a bug and the code works as is, but apparently only because of fortunate
timing: the browser started by the
See Chapter 4 for much more on output file closes (including rules of thumb which
the book failed to heed in this context), especially pages 137-141 and 145. The prior
edition strung the Later Findings: Some Machines Require Explicit Close
After seeing this issue manifest itself for very small HTML-only emails on a
much faster machine running a different operating system, I'm reclassifying this
as a correction to be patched in reprints and next example package version (1.2);
please see the
patch below.
When and where this problem occurs, an HTML-only email may open as a blank web
page, because its temporary file has not been flushed to disk. Oddly, on the
faster machine, the web browser somehow opens and reads the temporary file before
the GUI method has a chance to close it on exit. Moreover, this happens only for
very small emails (< 10K), suggesting a buffer size role. Adding an explicit
This issue is platform- and timing-specific; impacts just one minor aspect of a very large program; and, even when it does, can always be worked around in the user interface in three different ways—by pressing the web browser's refresh/reload, by viewing the extracted plain-text in the GUI's main window, and by clicking the sole HTML's part button in the main GUI window to open it on demand. Still, it's annoying and simple enough to merit a patch. For detail-minded readers, the faster machine with the incorrect behavior was a multicore Windows Vista machine; the book test machine where the code works as is was a single-core Atom Windows 7 machine (a beefy netbook). Since the Python method in question returns immediately after this code, on Vista a web browser apparently starts and opens a local web page faster than a Python method function can exit. This may reflect differences in the implementations of start commands in the two systems. I'd be surprised if this occurred on other platforms which spawn processes to open browsers; on the other hand, unpredictable timing has a way of being unpredictable. As described in the book, there are other issues related handling of HTML-only emails which I've left up to interested readers to address. As is, in lieu of an HTML-enabled text viewer, display of such emails employs a somewhat temporary scheme which was tested and used by just a single user on a single platform. For example, its single temporary-file model means only the last such email viewed is ever stored at any one point in time, regardless of how many are opened. Such oddness does not occur for HTML parts opened on demand, because their files are resaved and closed correctly in mailtools each time an open is requested. As for much of this system, improve as desired. Update, Oct-19-11 Per the release description above, this issue was patched and fixed in release 1.2 of the examples package, and the patch is present in all later PyMailGUI releases. This patch was also applied in reprints of the book itself. See the formal book patch description ahead. Using Timeouts for POP and SMTP Server Connections (Patched in 1.2)Short story: PyMailGUI must use timeouts on server connections to avoid hanging while waiting for interminable transfers. This support was added in early versions of the book's examples package and in the book's text itself, and is present in standalone PyMailGUI. This support has, however, been the scene of multiple revisions and Python changes, and makes for a convoluted and evolving story. The Issue
[Feb-1-11]
The email-based code in Chapters 13 (and its clients in Chapters 14 and 16)
should probably pass timeout arguments to the Update: Timeouts Patch for Next Reprint[Feb-22-11] I've now added the timeout arguments as patches to be made in the next reprint and examples package version (1.2): see the patch below. This became a priority when I started seeing the email server at my ISP suddenly failing to respond to connect requests on a very regular basis. This may have been a temporary problem at the ISP, but killing and restarting the email client's process manually was much more painful than patching to use timeouts for server connections. Update: More on Timeout Settings[Mar-17-11] If you wish to use PyMailGUI for real email work, you may need to increase its email transfer timeout values to accommodate slower Internet access speeds. As patched and shipped in the 1.2 examples package, both POP and SMTP timeouts are set to 20 seconds, which suffices in most cases. Especially for sending large emails over slow connections or slow servers, though, a higher SMTP timeout value such as 60 or more seconds may be required. See the patch ahead for the location of this value in the example code. Discussion: This is a surprisingly subtle issue, not covered in the book. POP and SMTP timeout values were added after the book's publication to avoid transfer threads hanging indefinitely—a scenario which may require manually killing the email client's process in worst cases. For instance, failure to contact the server on mail Load requests can render the GUI largely inoperative (loads preclude most other operations, including Quit). This is despite the fact that the load is run in a thread; the GUI itself remains active, but cannot perform most server-based email processing in this state. Passing timeouts when connected to email servers avoids this by triggering exceptions when server transactions hang, thereby terminating the server transfer thread and producing an error pop-up in the GUI. However, Python's library currently applies these timeouts naively to every server interaction step performed on the socket created for an email transfer—not just the initial connection calls, but also later data sends and receives. This makes the timeout setting sensitive to the speeds of email servers, the speed of your own Internet connection on the client, and message size in general. This is true for both fetches and sends (POP and SMTP), though it is more crucial for sends, which transfer a message's text all at once, than for fetches, which read messages line by line. Unfortunately, this seems a bit of a Catch-22—larger timeout values allow larger mails to be transferred on slow connections, but also mean that email transfer threads will be hung longer when servers are truly inactive. Moreover, the timeouts can't generally be omitted altogether, or the transfer threads may hang interminably—as mentioned, in worst cases this may block other user operations in the GUI, and require the email client's process to be killed manually when email servers become unresponsive (this was the original motivation for the timeout patch). Really, Python's email library modules should probably support different timeout settings for different operations; one for all doesn't quite make sense—sending a large email requires very different timeout treatment than initial connection—but that's the API that exists today.
Although it's possible to implement more custom transfer timeouts manually
instead of relying on the existing library module support (e.g., add top-level
timer code around initial connect calls only), this would require too many
post-publication code changes, and would not suffice if later operations hang.
In principle, it's also possible to selectively enable and disable timeouts for
the socket embedded in and used by the
For sends, timeouts also trigger what looks like a bug
in Python 3.1's standard library—the mail send appears to fail after
the mail's text has been fully sent and while trying to read the server's
truncated reply to it, but only because the socket
Summary:
Because of all this, in one of my own contexts I had to bump up the
SMTP timeout to 60 seconds to allow for sending a large email on a slow
network; otherwise, the send failed with an exception and an error pop-up.
Change likewise if and as needed for your context. Ideally, the mail
server timeouts would be configurable in the Update, Oct-19-11 Per the release description, this was eventually patched and fixed in release 1.2 of the examples package, as well as in reprints of the book itself. See the formal patch description ahead for changes made; timeout values are passed to POP and SMTP server objects at their connect calls. Naturally, all later PyMailGUIs inherit the fix.
Update, 2018
This story changed yet again with 2015's Python 3.5.
In brief, timeouts in Python 3.5's PyEdit: Minor Usability Tweaks and Suggestions (1 Patched in 1.2)[Jan-9-11] Chapter 11's PyEdit text editor is a large program with lots of functionality, which I use nearly every day in one context or another. Besides text edits, it's also a key component in the book's PyMailGUI email client. Still, like most non-trivial user interfaces, there are plenty of ways its interaction might be customized or improved, depending on its users' preferences. After using it recently with the more critical eye afforded by the passage of time, five items seem prime candidates for improvement; all are minor nits and not bugs, but would be simple to improve, and might make nice coding exercises:
Because PyEdit is a book example, written and provided in easily scriptable Python code, except as noted I'll leave applying these items as suggested exercises for readers, along with anything else you might care to tweak. This is Python, after all. Update, Oct-19-11 Per the release description above, one of the items listed here (focus loss) was patched in release 1.2 of the examples package, as well as in reprints of the book itself. See the formal patch description ahead. Update, Feb-2018 PyEdit has undergone major development in recent years, which addressed usability issues and limitations far in excess of those listed here. Its full set of post-publication changes is documented here. To get the latest PyEdit release with all the new enhancements, visit its web page. It's available as standalone executables for Mac, Windows, and Linux, plus a source-code package that's suggested follow-up study (if far too large to include in a book). While you're browsing, see also the standalone release of PyMailGUI and other programs, which have similarly evolved since their book appearances. Shelve close() Calls Not Required for Non-Update Scripts
[Feb-1-11]
A reader posted an errata report for this book on O'Reilly's site, which
claimed that a Type: Minor technical mistake Description: There are no page numbers when using the Kindle version of the text. In the discussion of building dictionaries using classes, Example 1-19 (dump_db_classes.py) requires closing the db at the end of the script. The final line of the code example should be: db.close() If the db is not closed, the subsequent updating (Example 1-20) and then re-printing of the db (using dump_db_classes.py again) will fail, giving an error code: Traceback (most recent call last): File "C:\Python31\dump_db_classes.py", line 6, in
I have not been able to reproduce this error, and suspect that the poster's
kindle cut-and-paste simply dropped the
Because I can't reproduce this issue, I'm posting this as a clarification
instead of a correction for now, barring a more detailed reader report.
If you do see the same error, please email me with full context; the platform,
Python version, and underlying DBM interface in use may factor into behavior
too, and there are too many possible combinations for me to test exhaustively.
In the poster's defense, shelves are notoriously error-prone; it's not impossible
that file paths may have differed between scripts (the current working directory
can sometimes change unexpectedly in IDLE), or that a bad cut-and-paste
dropped the Update Feb-2011 The reader who posted this note was later unable to reproduce the error in question by repeating the steps which led to it, but believes it existed initially. That may close the case, though there are too many variables related to shelves to be certain. General Book Marketing Question Replies[Jan-10-11] O'Reilly Media (the book's publisher) recently asked me for written replies on a few questions related to this book's scope, audience, and goals. Since this might help both current and prospective readers understand the book in general, I've cut and paste the replies on this page. tkinter: Linux/Mac Portability and Other Notes
[Nov-15-15]
Recent development on the Frigcal
calendar GUI has underscored a number of portability issues and other usage notes
regarding Python's Linux PortabilityIn sum, for programs run on Linux:
tkinter examples were developed and demonstrated on Windows 7,
and may require minor adjustments including the above for optimal use on Linux systems. The
vast majority of tkinter does work across platforms with no code changes, but top-level window
manager interfaces in particular are notoriously nonportable.
Other tkinter NotesIn addition to Linux use, the Frigcal program unearthed a number of noteworthy updates for
Update, Nov-2016 Per later porting, Mac OS X also poses a nontrivial set of Tk portability issues of its own; see this note elsewhere on this page for more details and Mac resource links. tkinter after() Callbacks Can "Hang" on Time Changes
[Nov-14-15]
Python's
After much puzzling, it was eventually determined that this occurs only when the system time has
been changed—for instance, on daylight savings time adjustments, or other automatic or manual
changes. And it turns out that this reflects a known issue in the Tcl/Tk library underlying
Python's
In short, the Tcl depends on the system time (converted to seconds from the start of the Unix epoch) increasing fairly close to monotonically for the correct behaviour of a number of things, but most particularly anything in the after command. Internally, after computes the absolute time that an event should happen and only triggers things once that time is reached, so that things being triggered early (which can happen because of various OS events) don't cause problems. If you set the system time back a long way, Tcl will wait until the absolute time is reached anyway, which will look a lot like a hang.
In PyMailGUI, this looks like a hang, but it's not. Really, the thread-queue checker's
There is no known fix to this. If your PyMailGUI appears to not be processing email
transactions, simply restore your system clock, or restart PyMailGUI. There is a good
chance that a future Tcl/Tk release may address this by using a "monotonic" clock:
one that has no reference point but can never go backwards, and so isn't susceptible
to such change. In fact, Python now has such an interface—see You Must Use Your Own FTP and Email Servers/Accounts[Nov-14-15] I've gotten numerous emails from readers who have trouble using some of the book's FTP and email Internet examples as coded in the book. In short, you must change the configuration settings in these scripts to use your own FTP server and email accounts. The CGI server-side scripting examples require no such change, as they run entirely locally—including their web server. I thought this was stated clearly in the book, but it's come up often enough to warrant pasting a reader query and reply on the subject here. > -----Original Message----- > From: .... > To: [email protected] > Subject: chapter 13 example > Date: Fri, 13 Nov 2015 16:35:41 -0800 > > I have a question on the getone.py example. When I run it the ftp.rmi. > net doesn't seem to work. I see you have changed to the learning python > site but when I use the new site the same problem occurs with the > password input. I've tried (), anonymous, and my email address. ? what > to do to connect. > I've been reading your books now for about 13mths. I'm > approaching this like learning a foreign language and enjoying it. I > haven't moved to 3.5 as the 3.4 v seems to work well. Thanks for any > help you can give. > Thanks for your note. Unfortunately, I do not maintain an FTP account for use by readers of the book. With many thousands of readers around the world, this would be too large a task and security risk. Instead, the assumption is that you will replace the site and login details with those of servers to which you have access, if you wish to run such code live. This also applies to the later email (and other) examples: please change configuration files to use your own account, as described in the book. The server-side examples are more immune to this, as they use a Python-coded server running locally on your machine. Best wishes on Python and the book, --Mark Lutz, http://learning-python.comBook CorrectionsIn a book this large there are bound to be a significant number of typos, and I don't plan on listing them all here. Instead, this section will collect those typos that at latest update time seemed most grievous to me on purely subjective grounds (of course, your subjective grounds may vary). The items here reflect patches made to the book itself in reprints; code patches too large for the book appear in the example package only. See O'Reilly's web page and its formal errata list for this book for the full list of typos collected and patched in reprints over time.
| |||||||||||||||||||||||||||
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |