Start any video training course for FREE. More than 500 to choose from. Learn more
Programming Python

Errata for Programming Python

Submit your own errata for this product.


The errata list is a list of errors and their corrections that were found after the product was released. If the error was corrected in a later version or reprint the date of the correction will be displayed in the column titled "Date Corrected".

The following errata were submitted by our customers and approved as valid errors by the author or editor.

Color Key: Serious Technical Mistake Minor Technical Mistake Language or formatting error Typo Question Note Update



Version Location Description Submitted By Date Submitted Date Corrected
PDF, Other Digital Version
Page xxviii
at top of page in continuation of previous paragraph

"Only a fraction of Python users must care about linking in C libraries today, and those who do already have the skills required to read the larger and more ***compete*** example of integration present in the source code of Python itself." Type at ***, suppose to be complete? It's in pdf and epub that I just got.

Note from the Author or Editor:
Yes - a typo. Please fix in reprints.

Anonymous  Dec 16, 2010  May 13, 2011
, Printed, PDF, Safari Books Online, Other Digital Version
Page xxviii
line 3 from page top

[Feb-1-11] Page xxviii, line 3 from page top: two typos in same sentence This text's "larger and more compete example" should be "larger and more complete examples".

Mark Lutz
 
Feb 02, 2011  May 13, 2011
Printed, PDF, ePub, Mobi, Safari Books Online, Other Digital Version
Page N/A
N/A

There is a new patch for running PyMailGUI under Python 3.3, which fixes a display issue for non-ASCII email address names introduced by an incompatible change in Python's email package. For details and the simple patch, please see: http://rmi.net/~lutz/pp4e-updates.html#py33emailfix

Mark Lutz
 
Sep 15, 2013 
Printed, PDF, ePub, Mobi, Safari Books Online
Page N/A
N/A

[Oct 2013, No Edits Required, informational only] There's a new release of the book's examples package, updated for Python 3.3. Examples in this 1.4 release work with all 3.X Pythons 3.3 and earlier (and possibly later). It's available at the book's official examples site: http://examples.oreilly.com/9780596158118/ For details on the minor changes incorporated, as well as 3.3 usage pointers, see the package's new README file at either the preceding site or here: http://www.rmi.net/~lutz/README-PP4E-PY33.html Note that all major examples tested run correctly on Python 3.3 (and 3.4), but some minor examples will reflect changed behavior in Python after 3.1. Most notably, the email package and CGI scripts mutated, though larger email and web examples still work as shown in the book with the patches listed above. If you find a deviation in book example behavior under later 3.X releases, consider it a valuable lesson; change is a fact-of-life in software in general, and open source in particular. Some such change is even beyond Python's scope; the recent trend towards using odd Unicode characters in emails, for instance, has potential to break many an email client, the book's clients included. Feel free to change as the future merits.

Mark Lutz
 
Oct 16, 2013 
PDF
Page N/A
tictactoe_lists.py line 274

For the score algorithm: def scoreMove(self, T1, T2): (row, col) = T1 ((countRows, countCols), (countDiag1, countDiag2)) = T2 return ( countCols.get((col, self.machineMark), 0) * 11 + countRows.get((row, self.machineMark), 0) * 11 + countDiag1[self.machineMark] * 11 + countDiag1[self.machineMark] * 11 + countCols.get((col, self.userMark), 0) * 10 + countRows.get((row, self.userMark), 0) * 10 + countDiag1[self.userMark] * 10 + countDiag1[self.userMark] * 10 + countCols.get((col, Empty), 0) * 11 + countRows.get((row, Empty), 0) * 11 + countDiag1[Empty] * 11 + countDiag1[Empty] * 11) It seems you counted the same diagonal (countDiag1) twice. Shouldn't you use countDiag2 as well? countDiag1[self.machineMark] * 11 + countDiag2[self.machineMark] * 11 countDiag1[self.userMark] * 10 + countDiag2[self.userMark] * 10 countDiag1[Empty] * 11 + countDiag2[Empty] * 11) Am I missing or assuming something wrong here???

Note from the Author or Editor:
[NO EDITS REQUIRED] Yes, column 2 should probably be counted per your post. But this code is in an external supplemental example, is not shown in the book, and is not used by the book's briefly-presented PyToe example, which selects moves with the much better Minimax search alternative in the referenced file. Hence, no update required, but the following provides some historical context for interested readers. This code is part of the PyToe tic-tac-toe game program. It appears in just 1 of the 5 move selection alternatives in the external example file (not counting variants never ported to 3.X form). It uses a very simplistic scoring heuristic, which was later subsumed by alternatives that proved better (and not just because of this typo). Frankly, I haven't seen this code since it was written for the 2nd Ed in 1999; it wasn't used after initial development, and has largely existed as cruft since then. Even the 2nd Ed did not list any PyToe source code, because it requires some AI background that was deemed beyond the book's scope, Since then, the 3rd and 4th Eds have continued to relegate PyToe to an external-only example, mentioned only as supplemental reading, and presented with just a screen shot and blurb to pique interest. Like the Holmes expert system similarly mentioned in the book, AI gaming is fun stuff, but out of scope in general. In other words, great catch: I'm amazed that this obscure code received scrutiny after 16 years.

Michael Basca  Feb 19, 2015 
PDF
Page N/A
"treeview_subclass.py" Line 87

For the following lines of code in treeview_subclass.py: parent.__colpos + Colsz*.25, # from x-y, to x-y parent.__rowpos + Rowsz*.5, colpos + Colsz*.25, rowpos, arrow='last', width=1) node.__rowpos = rowpos node.__colpos = colpos # mark node, private attrs You noted that __rowpos and node__pos are private attrs (name mangled). But is that really the case? Aren't you just assigning an attribute to an object that just so happens to have a double underscore and assigning a value to it rather than defining it in the class definition. For example: Class A: __x = 1 >>>A.__x AttributeError: type object 'A' has no attribute '__x' vs. Class A: pass A.__x = 1 >>>A.__x 1 Doesn't the fact that accessing the attributes in the following code: parent.__colpos + Colsz*.25, # from x-y, to x-y parent.__rowpos + Rowsz*.5, imply that they they aren't private? I could have just easily removed the underscores and the code would work just the same: parent.colpos + Colsz*.25, # from x-y, to x-y parent.rowpos + Rowsz*.5, colpos + Colsz*.25, rowpos, arrow='last', width=1) node.rowpos = rowpos node.colpos = colpos

Note from the Author or Editor:
[NO EDITS REQUIRED] No; sorry, but this post seems to reflect a lack of understanding of Python's pseudo-private attributes mechanism, an oddly obscure but very useful tool. Please see Learning Python for language fundamentals like this; as stated in the Preface, they are prerequisite to the applications-programming topics in Programming Python. One can't really jump into applications successfully without understanding language basics. In any event, this post refers to code included as a supplemental example but not listed or covered in the book itself, and the code referenced is not in error. As a brief review, though, pseudo-private names are coded with double underscore prefixes, and are expanded by Python at each of their appearances anywhere in the class. In this case, the double underscore names are used intentionally for administrative data added by the tree sketcher, so that they won't clash with attribute names used by the application whose trees are being sketched. Because each of the class's "__X" names is stamped with the class name automatically, they are different from the same name used in other classes. In simpler terms: >>> class TreeViewer: ... def __init__(self): ... self.rowpos = 88 # non-mangled: application's data ... self.__rowpos = 99 # mangled, pseudo-private: tool's data ... def update(self): ... self.__rowpos += 1 # update mangled tool name (only!) ... >>> tv = TreeViewer() >>> tv.__dict__ {'rowpos': 88, '_TreeViewer__rowpos': 99} >>> tv.update() >>> tv.__dict__ {'rowpos': 88, '_TreeViewer__rowpos': 100} >>> tv.rowpos 88 >>> tv._TreeViewer__rowpos 100 By mangling the names to include the enclosing class's name, Python more or less guarantees that they are unique, distinct from the attributes of any other class in an application, and not accessible from outside the class without using their fully-mangled form (in this case, obj._TreeViewer__rowpos) . It's not full privacy (see the decorators chapter in Learning Python 5E for an approach to implementing that with attribute tools), but suffices to minimize name collisions. If the code had just used "node.rowpos" without the underscores, it would possibly overwrite an attribute of the same name being used by the subject application.

Michael Basca  May 14, 2015 
Printed, PDF, ePub, Mobi, Safari Books Online
Page N/A
General note

[No Edits Required, Supplemental Page Note] There is a supplemental list of items posted to the errata page by reader Michael Basca in the first half of 2015, at this location: http://www.rmi.net/~lutz/more-reader-posts-PP4E.pdf This reader posted 48 notes in all -- a new record for my books. Of these, I've retained 16 posts in the errata list here that either warranted book patches, or were deemed to be of potentially broad interest. The remaining 31 posts (after removing 1 duplicate) were moved to the supplemental page, which includes: 1) Notes on changes in recent Python releases impacting book examples. 2) Usage pointers for Mac/Linux users, regarding tkinter and web servers. 3) A few untested patches for Python library changes (e.g., nntplib, PyCrypto, urllib.request). We can't update this book for changes in Python after its publication, of course, and such issues would naturally be isolated and addressed in a next edition, if one ever appears. The goal of the supplement posts page is to provide a resources for readers who may be stumbling onto the same issues. Note to reprints: none of the items on the supplemental page require book edits.

Mark Lutz
 
Aug 02, 2015 
Printed, PDF, Safari Books Online, Other Digital Version
Page 12
5th Python prompt

Python prompt has two angled-brackeds, instead of three: >> bob2['job'][-1] should read: >>> bob2['job'][-1]

Note from the Author or Editor:
Yes -- add an extra ">" to the ">>" prompt here (it should be ">>>").

Daniel Díaz  Mar 24, 2011  Nov 11, 2011
Printed
Page 21
Example 1-7 heading

The Example 1-7 heading lists the filename as update-db-pickle.py when it should be update_db_pickle.py.

Note from the Author or Editor:
Yes -- fix as described (use underscores instead of dashes to match the file's name in later interaction).

Brad Trotter  May 24, 2011  Nov 11, 2011
Printed
Page 38/39
example 1-22

example 1-22 peopleinteract_update.py: Neither my typed code nor the cut and paste code from the online example code at O'reilly produce the result printed in the paperback edition. This code contains both formatting errors and logic errors.

Note from the Author or Editor:
This reflects a bug in Python 3.2.0, not in the book's examples. Please see: http://www.rmi.net/~lutz/lp4e-updates-notes-recent.html#py320inputbug for details. In short, Python's input() built-in is broken in 3.2.0 (3.2) when used in Windows console mode only. This built-in has been fixed in later Python releases. The quickest fix is to upgrade to 3.2.1 or later, or try a different environment; examples in the book which use input() work fine in all other Python versions and in most other contexts such as IDLE.

Charles Wehrenberg  Dec 14, 2011 
Printed
Page 63, 67
markup code

Because of the evolving html standard, as of the publication for the fourth edition of this book, the html table elements (<tr>, <th>, <td>) should specify closing code (</tr>, </th>, </td>.

Note from the Author or Editor:
[No change required] The book states clearly that it omits some HTML tags on purpose for simplicity and space. I agree with this poster's point in principle, but it doesn't merit changes in the book given its explicit and broad statements on this point.

charlie@solozone.com  Dec 01, 2011 
Printed, PDF, ePub, Mobi
Page 121
line -7 of example 3-8

EDIT: Change the referenced code line from the first of the following to the second (only adding 'y' and 'Y' in the bracketed ilst, and using straight quotes): if lines and getreply() not in [b'y', b'Y']: if lines and getreply() not in [b'y', b'Y', 'y', 'Y']: break DISCUSSION: A reader named Zhaoliang reported this on bookquestions@oreilly.com. My reply follows: This looks like a minor but valid bug to me. To support all its target use cases, the code line in question (line -7 of example 3-8 on Page 121) should indeed be changed from the first of the following to the second (adding 'y' and 'Y'): if lines and getreply() not in [b'y', b'Y']: if lines and getreply() not in [b'y', b'Y', 'y', 'Y']: break Otherwise, the code: 1) *Works* for NON-TTY cases, regardless of user input. In these cases, stdin is a file or pipe, and msvcrt.getche() is used for user input. Command lines take this form: python moreplus.py < inputfile type inputfile | python moreplus.py 2) *Fails* for TTY cases, but only if user input is 'y' or 'Y'. In these cases, stdin is a console, and the builtin input() is used for user input. Command lines take this form: python moreplus.py inputfile The reason #2 fails is that input() returns a str string, but msvcrt.getche() returns a bytes; to allow for _either_, we need to include both bytes and str in the response list. For simplicity, you might also code the line this way: if lines and getreply().lower() not in [b'y', 'y']: break I don't recall the history on this example, but it was likely either not retested in all usage contexts (perhaps 'y' was not verified); assumed a pending 3.X library change that never appeared (return types probably should be consistent); or was inadvertently tested under Python 2.X (though that's unlikely, given its 3.X input() call). Thanks to the reader for the notification; I will post this as an errata for the book, to be repaired in the next reprint, which is coming up early next month.

Mark Lutz
 
Jul 31, 2015  Aug 07, 2015
Printed
Page 152
2nd example

Reads bytes = file.read() values = struct.unpack('>>i4shf', data) NameError: name 'data' is not defined Should read as data = file.read() values = struct.unpack('>>i4shf', data)

Note from the Author or Editor:
Yes -- change as described: page 152, 2nd code listing, line 4 should read as follows (change "bytes" at the end to "data"): values = struct.unpack('>>i4shf', data) The code actually works as is if you keep typing all the code on this page in sequence (as I must have done), because "data" is what we called the byte string when it was written to the file; that is, "data" from the first interaction is the same as the "bytes" read off the file in the second interaction. This wasn't the intent, though.

Bob Sanford  May 24, 2011  Nov 11, 2011
Printed
Page 152
first example; second line

Running Python 3.2.2 on Win 7 machine EXISTING data = struct.pack('>i4shf', 2, 'spam', 3, 1.234) NEEDS BINARY b & SHOULD READ data = struct.pack('>i4shf', 2, b'spam', 3, 1.234) this correction is suggested by the values = return in the second example.

Note from the Author or Editor:
This reflects a recent change in Python 3.2, not a problem with the book examples. In short, 3.2 has removed existing struct.pack functionality for str strings and the "s" type code, and now allows only bytes strings in this context. In 3.2 and later, you must manually encode Unicode str to bytes prior to this tool, using str.encode() or bytes(). This change also impacts some examples in Learning Python, and one example in Python Pocket Reference. For more details, including the fix, please see this note on my book update pages (or its cross-post on Programming Python's updates page): http://www.rmi.net/~lutz/lp4e-updates-notes-recent.html#py32structchange I can't post here about every change in Python that will impact the books over time, but this change seemed to merit a few words.

Charles Wehrenberg  Jan 07, 2012 
Printed, PDF, ePub
Page 322
code block 2

"C:\...\PP4E\Tools> python find.py *.py .. | more" It seems I have to quote "*.py" for this command to work in Linux. Didn't try Windows though.

Note from the Author or Editor:
Changing this to a clarification, not an errata. To address, change the very end of paragraph 2 on Page 322 from: "...standard input stream:" to: "...standard input stream (remember to quote the "*.py" on Unix and Linux shells only, to avoid premature pattern expansion):" [DISCUSSION ONLY FOLLOWS] The report is correct about needing to quote some command-line arguments on Linux (only), and this does merit a note here. This finder directory tree search script matches the passed-in "*.py" pattern itself, so we don't want a Linux shell to do expansion before it's passed in. However, shell differences are mentioned elsewhere; this book runs all its examples on Windows, where this isn't an issue; and the book cannot note shell differences at each command where syntax diverges without becoming a shell programming guide too. On this specific point, the following text appears on Page 106 (before the command line in question) in an early section devoted to command lines in general: """ (portability note: you may need to add quotes around the *.py in this and other command-line examples to prevent it from being expanded in some Unix shells): """ Moreover, Unix shell globbing behavior is also described on the earlier Page 166, and the closer Page 320-321. Both linear readers of the book and Linux users in general should probably be aware of the issue well enough to argue against redundant warnings throughout an already large text (and quoting arguments in general for Linux readers would likely confuse others with less command-line experience to draw from). Nevertheless it's worth adding the text in the book and retaining this note as a reminder for Linux readers here -- thanks for the report.

Yang Lifu  Sep 09, 2013  Jan 17, 2014
PDF
Page 323
1st paragraph/sentence

Last sentence of 322 going into 323: "Here’s a more complex example of our find module at work: the following system command line lists all Python files in directory C:\temp\PP3E whose names begin with the letter q or t. Note how find returns full directory paths that begin with the start directory specification:" Requested change: "q or t" --> "q or x" As per example code.

Note from the Author or Editor:
Yes, change the referenced text to "q or x". (Most likely a last-moment change, but very minor, and likely obvious given the multiple surrounding examples that search for q or x, as noted by the poster.)

Michael Basca  Dec 26, 2014  Aug 07, 2015
PDF
Page 325
2nd Paragraph or 2nd code block

Original Command "C:\...\Examples\PP4E> Tools\cleanpyc.py" Should be: "C:\...\Examples\PP4E> Tools\cleanpyc.py .." Since the output shows the the .pyc files being removed in the parent directory tree.

Note from the Author or Editor:
[NO EDITS REQUIRED, informational only, changed to clarification] Not true. A ".." wouldn't hurt, but is not required here. When running the script from one level up in the shell, the current working directory (CWD) used by default is the directory the shell is working in, not the script's own directory. Using Python 3.3, in a Windows shell (Command Prompt): C:\...\PP4E> Tools\cleanpyc.py => C:\...\PP4E\Ai\TicTacToe\__pycache__\tictactoe_lists.cpython-33.pyc => C:\...\PP4E\Dbase\__pycache__\testdata.cpython-33.pyc => C:\...\PP4E\Dbase\__pycache__\__init__.cpython-33.pyc => C:\...\PP4E\Dstruct\Classics\__pycache__\btree.cpython-33.pyc This is why the immediately-following example in the book is run one level down, in the scripts own directory, to illustrate the difference: C:\...\PP4E\Tools> cleanpyc.py . => .\find.pyc => .\visitor.pyc => .\__init__.pyc Found 3 files, removed 3 For a refresher on this, see "CWD, Files, and Import Paths" on page 104.

Michael Basca  Dec 26, 2014 
PDF
Page 329
Note at the end of "A Python Tree Searcher"

The second paragraph discussing the textexts list used in the program states: "Also notice the textexts list in Example 6-17, which attempts to list all possible binary file types ..." The list actually contains text file types (.py, .pyw, .txt, etc), not binary file types.

Note from the Author or Editor:
Yes. I believe the example number may have been off here (there's a skipexts binary file types list ahead in Example 6-18), but it's simpler to adjust the text as it is. At the referenced note location, change the start of line 2 from the first of these to the second: "possible binary file types:" "possible text file types:"

Jason  Oct 01, 2014  Aug 07, 2015
PDF
Page 344
3rd paragraph

Original line of code: def trace(*args): print(*args) # with spaces between Should be: def trace(*args): print(args) # with spaces between The asterisk should be removed in the print statement.

Note from the Author or Editor:
[NO EDITS REQUIRED, retained as informational, changed to clarification] No, the star is required. This is a common pattern for general trace routines; the first star in the header means "collect any number of positional arguments in a tuple", and the star in the print() call means "unpack the arguments tuple into separate arguments". The combined effect allows any number of arguments, and passes them on to print() so that they display individually, with spaces between them, and without enclosing tuple parenthesis: >>> def trace(*args): print(*args) # with spaces between ... >>> trace('spam', 99, 3.1415) spam 99 3.1415 >>> trace('spam') spam See Learning Python for more background on such language fundamentals.

Michael Basca  Dec 27, 2014 
Printed, PDF, ePub
Page 442, 564, etc.
win.grab_set() paragraph, grids, etc.

[Last changed August 2015, No Edits Required, informational only] ASSORTED TKINTER GUI NOTES: 1) Dialogs and wait_visibility() on Linux (page 442) On Linux, you probably need to call win.wait_visibility() before win.grab_set() when creating a modal dialog this way. This platform disallows grabs until a window is visible; without the added call, the grab fails with an exception and the dialog isn't modal. This book's examples were run and tested on Windows where the extra call isn't required, and there's unfortunately no room to insert a note on this page. I'm posting it here as a clarification instead. For more on this call, see its usage in the calendar program example I posted as a supplement for book readers at: http://learning-python.com/frigcal/Readme-frigcal.html The call is demonstrated in this program's file frigcal.py, using this code: if sys.platform.startswith('linux'): window.wait_visibility() window.grab_set() 2) Uniform gridding: tables (page 564) The frigcal program and file also illustrates uniform-sized grids, similarly not shown in the book. It uses the following code (experiment on your own to see its effect): for week in range(MAXWEEKS): alldaysfrm.rowconfigure(week, weight=1, uniform='a') for day in range(7): alldaysfrm.columnconfigure(day, weight=1, uniform='a') 3) Unicode limitations The Tk library underlying Python's tkinter has also been shown to have limits with respect to allowable Unicode characters. Odd emoticons in emails, for example, can wreak havoc with email clients like the book's PyMailGUI; code workarounds as warranted (e.g., sanitize text before storing in GUI text fields). 4) Widget.after() hangs Finally, it's been recently discovered that the tkinter widget.after() timer event can be broken by changes to the system time. In short, the underlying Tk library computes an absolute time for running a scheduled after() event. If Windows automatically adjusts your clock, pending after() callbacks may appear to hang, because their absolute firing time is not reached. This can manifest in the book's PyClock clock and PyMailGUI email client examples, as both rely on timer events (to redraw clocks, and run queued thread actions). This is a Tk issue, and may be repaired in future Tk releases; for now, try changing your clock to unhang such programs.

Mark Lutz
 
Oct 18, 2014 
Printed, PDF, ePub, Mobi, Safari Books Online
Page 631
Source code def configBorders

The method of setting a window icon as used in the generic _window class, does not work on linux. This seems to be part because the .ico file is only for windows and part because tk has a hard time decoding any image file. Following code seems to work: root = Tk() img = PhotoImage(file='your-icon') root.tk.call('wm', 'iconphoto', root._w, img)

Note from the Author or Editor:
[No Edits Required: informational only, changing this report's type from minor technical mistake to clarification.] It's true that Windows ".ico" files won't generally work on Linux, but: 1) This is pretty clearly explained in a big paragraph on page 424, where tk's iconbitmap call is first covered in depth, and mentioned parenthetically on page 44 at a preview example (plus, the book makes its use of Windows for running examples explicit throughout). 2) The _window class on Page 631 referred to in this post should not cause its clients to fail on Linux, as it wraps the icon call in a exception handler and simply ignores the error on other platforms (to be verified, but it should only skip the custom window icon step and continue). So, this isn't an errata per se; the example works as shown, and requires tweaking outside Windows for custom icons as described in the book. That's one of the unavoidable platform dependencies of GUIs, and it wasn't possible to cover every variant. That said, I'm retaining this note here as a constructive and useful pointer for other Linux readers who may want to use a custom window icon too; thanks for the suggestion. On Linux, you'll probably also want to customize the _window class's iconpatt string, used to search for an icon file automatically if none is passed in (see the code: it's "'*.ico" as is).

Rob van der Most  Oct 06, 2013 
, Printed, PDF, Safari Books Online, Other Digital Version
Page 678
line 3 of last paragraph on page

[Feb-1-11] Page 678 in Chapter 11, line 3 of last paragraph on page, figure description off The text misstates Figure 11-4's content here: it does not show a Clone window (the original version of this screenshot did, but was retaken very late in the project to show Grep dialogs with different Unicode encodings). To fix, change this line's "a window and its clone" to read "a main window".

Mark Lutz
 
Feb 02, 2011  May 13, 2011
, Printed, PDF, Safari Books Online, Other Digital Version
Page 702 and 704
see detailed description

[For a detailed description of this item, as well as the correct whitespace in the patch, please see: http://www.rmi.net/~lutz/pp4e-updates.html#closenote http://www.rmi.net/~lutz/pp4e-updates.html#closepatch ] [Feb-1-11] Page 702 and 704, PyEdit: add text.focus() calls after askstring() Unicode popups For convenience, and per the detailed description above, we should add a call to reset focus back to the text widget after the Unicode encoding prompt popups which may be issued on Open and Save/SaveAs requests (depending on texconfig settings). As is, the code works, but requires the user to click in the text area if they wish to resume editing it immediately after the Unicode popup is dismissed; this standard popup itself should probably restore focus, but does not. To fix, add focus calls in two places. First, on page 702, at code line 21 at roughly mid page, change: if askuser: try: text = open(file, 'r', encoding=askuser).read() to the following, adding the new first line (the rest of this code is unchanged): self.text.focus() # else must click if askuser: try: text = open(file, 'r', encoding=askuser).read() Second, on page 704, at code line 8 near top of page, similarly change: if askuser: try: text.encode(askuser) to the following, again just adding the new first line: self.text.focus() # else must click if askuser: try: text.encode(askuser) Reprints: please let me know if there is not enough space for the inserts; I'd rather avoid altering page breaks in the process. This patch will also be applied to future versions of the book's examples package; in the package, the code in question is in file PP4E\Gui\TextEditor\textEditor.py, at lines 298 and 393.

Mark Lutz
 
Feb 02, 2011  May 13, 2011
PDF
Page 744
Middle page line 234 of source code

def traceEvent(label, event, fullTrace=True): print(label) if fullTrace: for atrr in dir(event): if attr[:2] != '__': print(attr, '=>', getattr(event, attr)) This line: for atrr in dir(event) Should be: for attr in dir(event)

Note from the Author or Editor:
Yes, change "atrr" to "attr" in the code referenced. This is near the end of example 11-18, in function traceEvent, in line "for atrr in dir(event):". (This code is never used, due to the fullTrace parameter aways being False; still worth a fix.)

Michael Basca  Feb 18, 2015  Aug 07, 2015
PDF
Page 834
Above last paragraph

In line 27 of test-stream-modes.py: # FAILS on open: text must be unbuffered I believe should be: # FAILS on open: text must be buffered or: # FAILS on open: text must be fully buffered

Note from the Author or Editor:
Yes; this is in the last line of example 12-12. Change the comment text on the right to "# FAILS on open: text must be buffered" (that is, change just "unbuffered" => "buffered"). This is just a comment and is implied by the surrounding narrative that describes this correctly, but merits a fix.

Michael Basca  Feb 24, 2015  Aug 07, 2015
PDF
Page 839
1st sentence

The net effect is that -u still works around the steam buffering issue should be: The net effect is that -u still works around the stream buffering issue

Note from the Author or Editor:
Yes, change "steam" to "stream" as suggested.

Michael Basca  Feb 25, 2015  Aug 07, 2015
PDF
Page 896 & 899
in 896 line 7 in code of cleanall.py; in 899 2nd paragraph

In references to directory and file: Tools\Scripts\ftpmirror.py They do not exist.

Note from the Author or Editor:
[NO EDIT REQUIRED, retained as informational only] No, Tools\Scripts\ftpmirror.py does exist, at least as of Python 3.3, in the standard Windows install. This post refers to a cryptic program comment and brief narrative mention that refer to Python's ftpmirror script as another example to study, as it's related to the FTP directory tree deletion script in the book. This script has been standard on Windows installs for many years, but has moved in the past, and may be elsewhere on Macs or Linux. Run a find to locate if needed, and try a web search or Python's source-code package as a last resort. This isn't discussed further in the book than this brief comment mention, so no elaboration is required.

Michael Basca  Mar 03, 2015 
, Printed, PDF, Safari Books Online
Page 963, 970
Page 963 line 9, and page 970 line 4

Page 963 line 9, and page 970 line 4: add timeout arguments to email server connect calls For robustness, add "timeout=15" arguments to the POP and SMTP connect calls, so that email clients don't hang when email servers fail to respond. In the book, change code line 9 on page 963 from the first of the following to the second: server = smtplib.SMTP(self.smtpServerName) # this may fail too server = smtplib.SMTP(self.smtpServerName, timeout=15) # this may fail too Similarly, change code line 4 on page 970 from the first of the following to the second: server = poplib.POP3(self.popServer) server = poplib.POP3(self.popServer, timeout=15) In the book examples package, these changes would be applied to line 153 of mailSender.py, and line 34 of file mailFetcher.py, both of which reside in directory PP4E\Internet\Email\mailtools. They'll be patched in a future examples package version. Not a bug, but a desired enhancement. For more background on this, see my updates page: http://www.rmi.net/~lutz/pp4e-updates.html#timeoutnote

Mark Lutz
 
Feb 22, 2011  May 13, 2011
PDF
Page 966
line 14 & 15 or 325 & 326 in mailSender.py code

For: class MailSenderAuth(MailSender): """ use for servers that require login authorization; client: choose MailSender or MailSenderAuth super class based on mailconfig.smtpuser setting (None?) """ smtpPassword = None # 4E: on class, not self, shared by poss N instances def __init__(self, smtpserver=None, smtpuser=None): MailSender.__init__(self, smtpserver) In: def __init__(self, smtpserver=None, smtpuser=None): MailSender.__init__(self, smtpserver) Need to initialize with tracesize similar to MailSender class: def __init__(self, smtpserver=None, smtpuser=None, tracesize=256): MailSender.__init__(self, smtpserver, tracesize) Or else you'll get error message not recognizing tracesize=5000 on line 24 of selftest.py.

Note from the Author or Editor:
Yes; this is a minor but tricky code change, so please ask if unclear. On page 966, change the class in question as described, adding just ", tracesize=256" to the "def __init__" header line, and " , tracesize" to the line following the header: class MailSenderAuth(MailSender): ... def __init__(self, smtpserver=None, smtpuser=None, tracesize=256): MailSender.__init__(self, smtpserver, tracesize) DISCUSSION: This was detected in test code that was never run for the book, because the test server didn't require authentication; the non-authenticated branch was always run instead. Also note that this is only used in a trivial self-test script; the authenticated sender class itself works fine, and has been used for years to communicate with an ISP that requires logins for sends in the book's PyMailGUI client. No other clients attempt to pass in a tracesize. We could just remove tracesize from selftest.py, but that seems like cheating...

Michael Basca  Mar 14, 2015  Aug 07, 2015
, Printed, PDF, Safari Books Online, Other Digital Version
Page 978, 964
mid page (see description)

[Oct-20-11] Pages 978 and 964, encode and decode i18n attachment filenames for display, save, send Per the detailed description at http://www.rmi.net/~lutz/pp4e-updates.html#filenamespatch, the following two changes will support both receipt and send of encoded i18n attachment filenames, assuming that such non-ASCII filenames are valid on the underlying platform (Windows is very liberal in this regard). First, on Page 978, change the very last line of the partName method def statement from the first of these to the second (this is mid page at code line 26, in file PP4E\Internet\Email\mailtools\mailParser.py -- be careful of indentation of the code and its "#" comment which is given more exactly in the detailed description named above): return (filename, contype) return (self.decodeHeader(filename), contype) # oct 2011: decode i18n fnames Second, on Page 964, change the 5th and 4th last lines of the addAttachments method def statement from the first of these to the second (this is mid page line -22, in file P4E\Internet\Email\mailtools\mailSender.py): # set filename and attach to container basename = os.path.basename(filename) # set filename (ascii or utf8/mime encoded) and attach to container basename = self.encodeHeader(os.path.basename(filename)) # oct 2011 These were also patched in version 1.3 of the book examples package (PP4E-Examples-1.3.zip); see http://www.rmi.net/~lutz/pp4e-updates.html#pymailguiall for details.

Mark Lutz
 
Oct 20, 2011  Nov 11, 2011
, Printed, PDF, Safari Books Online, Other Digital Version
Page 1072
code line 10 from top of page

[For a detailed description of this item, as well as the correct whitespace in the patch, please see: http://www.rmi.net/~lutz/pp4e-updates.html#closenote http://www.rmi.net/~lutz/pp4e-updates.html#closepatch ] [Feb-1-11] Page 1072, code line 10 from top of page, PyMailGUI: add a close() for HTML mail files For portability, and per the detailed description above, we should add an explicit close() call to flush the temporary file of an HTML-only email before starting a web browser to view it, so that this code works in all contexts. As is, it works on the test platform used for the book, and likely works on most others, because the method in question exits and thus reclaims, closes, and flushes the file before the spawned web browser gets around to reading it. However, this is timing and platform dependent, and may fail on some machines that start browsers more quickly; its been seen to fail on a fast Vista machine. To fix in the book, change the middle line of the following three current code lines: tmp = open(tempname, 'wb') # already encoded tmp.write(asbytes) webbrowser.open_new('file://' + tempname) to read as follows, adding the text that starts with the semicolon (I'm combining statements to avoid altering page breaks): tmp = open(tempname, 'wb') # already encoded tmp.write(asbytes); tmp.close() # flush output now webbrowser.open_new('file://' + tempname) In the book's examples package, this code is located at line 209 in file PP4E\Internet\Email\PyMailGUI\ListWindows.py; it will be patched there too in a future examples package release (version 1.2, date TBD).

Mark Lutz
 
Feb 02, 2011  May 13, 2011
PDF
Page 1219
Bottom of page in putflie.py comments

caveat: could open output file in text mode to wite receiving platform's line wite => write

Note from the Author or Editor:
Yes, in line 1 of paragraph 2 in code comments section, change the "mode to wite" to "mode to write". This is just cryptic and not grammatically-correct code comments text, but worth an edit.

Michael Basca  Apr 03, 2015  Aug 07, 2015
, Printed, PDF, Safari Books Online, Other Digital Version
Page 1226
sidebar on page

[Feb-1-11] Page 1226, two filename typos in same sidebar This will probably be obvious to most readers who inspect the external example files referenced here, but in this sidebar: "test-cgiu-uploads-bug*" should read "test-cgi-uploads-bug*", and the bullet item text "test-cgi-uploads-bug.html/py saves the input stream" should read "test-cgi-uploads-bug2.html/py saves the input stream".

Mark Lutz
 
Feb 02, 2011  May 13, 2011
PDF
Page 1238
Bottom of the page last sentence

The following sentence: The server’s classes’ implementation varies over time, but if changes to your CGI scripts have no effect, your platform my fall into this category: try stopping and restarting the locally running web server. Needs the word 'my' to change to 'may'.

Note from the Author or Editor:
Yes, change the referenced "your platform my fall into" to "your platform may fall into".

Michael Basca  Apr 03, 2015  Aug 07, 2015
Printed
Page 1280
Bottom of the page

I think this is a typo? from Crypto.Cipher import AES>>> AES.block_size16 When i plugged this into the interpreter python yielded a syntax error due to the '>>>' I changed it just to: from Crypto.Cipher import AES and followed the steps to receive the same results. (cypher text is now bytes vs. string in Python 3.4)

Note from the Author or Editor:
Yes, change this line to the following, where its "#" aligns vertically with the "#" in the line following it: >>> from Crypto.Cipher import AES # AES.block_size is 16 DISCUSSION: It appears that this reflects a conversion error from the 3rd edition's material. In the 3rd edition, this was the 3 lines that follow (with incorrect bold formatting on some), intended to show that block size is named in this library that's only thinly documented by the book: >>> from Crypto.Cipher import AES >>> AES.block_size 16 In the 4th edition, the conversion to MS-WORD for editing munged these 3 lines into 1, which eluded all later proofing. We don't appear to have space to restore the 3rd Ed's form, so making the text a comment will suffice. There's nothing we can do in this edition about the change from str to bytes in PyCrypto, unfortunately; it's too much code to change, and would not apply to or work for users of earlier Pythons that this edition addresses. Such updates are in the realm of a future edition.

Michael Basca  Apr 07, 2015  Aug 07, 2015
PDF
Page 1308
Last line 2nd bullet.

Original line: Pythons without any of these automatically fall back on an all-Python and always-present implementation called dbm.dumb, which is not really “dumb,” or course, but may not be as fast or robust as other options. or course => of course

Note from the Author or Editor:
Yes; please change as described, to "of course" (of course...)

Michael Basca  Apr 08, 2015  Aug 07, 2015
PDF
Page 1357
Top of the page.

from PP4E.Dbase.testdata inport Actor inport => import

Note from the Author or Editor:
Yes, change "inport" to "import" as described. In an unrun code snippet, not a formal example or examples file, but still worth a patch.

Michael Basca  Apr 14, 2015  Aug 07, 2015
PDF
Page 1412
2nd to last paragraph

Last sentence from 3rd paragraph: Although such parsing can also be achieved with more powerful tools, such as the regular expressions we’ll meet later in this chapter, split-based parsing is simper to code in quick prototypes, and may run faster. simper --> simpler

Note from the Author or Editor:
Yes: change the referenced "simper" to "simpler".

Michael Basca  May 10, 2015  Aug 07, 2015
, Printed, PDF, Safari Books Online, Other Digital Version
Page 1555
heading line at top of page

[Feb-1-11] Page 1555, top of page, quotes are misplaced in heading line A typo inherited from the prior edition: the quotes and question mark in the heading line at the very top of this page are slightly off. Change the heading line: So What’s “Python: The Sequel”? to read as: “So What’s Python?”: The Sequel. This header refers back to the sidebar in the Preface titled "So What's Python?". Arguably trivial, as this sidebar was 1500 pages (and perhaps a few months) ago by this point in the book, but it would be better to get this right. This header was broken by a copyedit change on the prior edition, and fell through the cracks on this one.

Mark Lutz
 
Feb 02, 2011  May 13, 2011