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.
Version |
Location |
Description |
Submitted By |
Date submitted |
Date corrected |
Printed |
Page 16
2nd sentence |
"When the action is competed, ..."
should be:
"When the action is completed, ..."
^
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 17
2nd code snippet, 2nd line |
"Connection to port 80."
should be:
"Connected to port 80."
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 18
Example 2.5. portscan.py |
"from connectiontester import testConnect"
should be
"from connectiontest import testConnect"
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 18
Example 2-5 |
The testConnect function is imported from the previous example. The
import statement uses "connectiontester" as the module name but the
previous example uses connectiontest.py as the file name.
|
Anonymous |
|
|
Printed |
Page 19
Example 2-6 dataforward.py |
Inside Example 2-6 dataforward.py, the second line is::
from twisted.protocols import basic
However, basic is not used anywhere in the example.
Note from the Author or Editor: Good catch. That import statement can be removed.
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 19
Example 2-6 dataforward.py |
The dataforward.py program does not work under Windows XP, Python 2.4.3, Twisted
2.4.0.
I copied the example inside t.py. Once started, no echo is done when typing from the
console. The program does not read stdin and does not forward it in the connection.
I had to hit Ctrl-C to close it and you can see that what was typed at the console
was not taken by the program.
If twisted.internet.stdio.StandardIO is not working on Win32 systems, the book should say so.
...
D: mp>HEAD / HTTP/1.0
==> / <==
HEAD: error reading `/': Is a directory
HEAD: cannot open `HTTP/1.0' for reading: No such file or directory
Note from the Author or Editor: This is true - a note should be added that this example does not work on Windows.
|
Anonymous |
|
|
Printed |
Page 22
bottom |
"How does that work?" is included in the code block, not as a section heading.
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 22
Example 2.7 |
The code printed in the book is out of date. The code in the current example code zip already fixes this problem.
The new code is listed below:
from twisted.internet import reactor, protocol
from twisted.protocols import basic
class EchoProtocol(basic.LineReceiver):
def connectionMade(self):
print "Connection from", self.transport.getPeer().host
def lineReceived(self, line):
if line == 'quit':
self.sendLine("Goodbye.")
self.transport.loseConnection()
else:
self.sendLine("You said: " + line)
class EchoServerFactory(protocol.ServerFactory):
protocol = EchoProtocol
if __name__ == "__main__":
port = 5001
reactor.listenTCP(port, EchoServerFactory())
print "Server running, press ctrl-C to stop."
reactor.run()
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 23
at least on line 2 |
Page 23, at least on line 2: typo LineReciever should be LineReceiver.
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 27
1st paragraph, 2nd sentence |
SHould read:
"This means that when the result of client.downloadPage comes in, the
reactor will call returnFilename with the result of client.downloadPage
as the first argument and the filename as the second argument."
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 30
Code listing, primarily the encodeForm() function |
Figure 3-1 actually indicates an error, not a successful validation as the main text suggests. In fact, an error _is_ returned if the sample code is executed, for reasons discussed below.
The format of multipart/form-data data blocks is given by section 7.2.1 of RFC 1521.
The validate.py code does not define a (required) "boundary" parameter value in the enclosing Content-Type header field. For the purposes of further discussion, however, this value will be assumed to be the 20 character string derived from the the randomChars list generated in encodeForm.
The encodeForm function does not create a properly-formatted multipart/form-data data block.
Within a multipart/form-data data block, each body part must begin with an encapsulation boundary, defined as two hyphens, followed by the "boundary" parameter value from the enclosing Content-Type header field, followed by a CRLF pair. The final part must be trailed by a special encapsulation boundary. This special encapsulation boundary has an additional two hyphens inserted before the final CRLF pair. All encapsulation boundaries, except the first, must be preceeded by CRLF pairs.
The validate.py code's encapsulation boundaries, with the exception of the first and last, are comprised of a 2 CRLF pairs, followed by 3 hyphens, the boundary string, another 3 hyphens, and a CRLF pair.
The validate.py code's first encapsulation boundary is like its others, except it lacks the 2 preceeding CRLF pairs.
The validate.py code's last encapsulation boundary is like its others, except it lacks a trailing CRLF.
None of these encapsulation boundaries is correct.
Additionally, the validate.py code does not insert blank lines between the header and body content of body parts.
Finally, the W3C validator service won't properly validate XHTML files, unless the relevant body part includes a Content-Type header specifing application/xhtml+xml. Such a header is not inserted by the validate.py code.
Note from the Author or Editor: The comments here are correct, but this example is actually quite of date now. twisted.web not includes parsing of multipart/form-data.
|
Anonymous |
|
|
Printed |
Page 35
Example 3-6 : function pagePart(), wrong indentation |
Lines 17-20 of Example 3-6 should be indented like this:
else:
percent = '%dK' % (self.currentLength/1000)
print "�33[1FProgress: " + percent
return client.HTTPDownloader.pagePart(self, data)
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 43
the html in the renderHomePage code reads - |
<title>Form Test</html>
when it should read -
<title>Form Test</title>
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 43
First paragraph, second sentence |
The text reads, "MyRequestHandler uses SetHeader to set the Content-Type header to text/html"... However, this call to SetHeader
doesn't appear anywhere in the example code on page 41!
This paragraph should read:
The Request class also provides a setHeader method for adding headers to
the response. For example, you can use setHeader to add a Content-Type
header indicating the type of content in the response body.
setHeader('Content-Type', 'text/plain') would generate the HTTP header
Content-Type: text/plain, telling the browser that the response is plain
text. If you don't manually set a Content-Type header, the Request class
will default to sending the Content-Type for HTML documents, text/html
(as it does when you run Example 4-2).
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 45
3rd line from bottom |
The sentence ending in "send the form data to the page formhandler using an HTTP POST request" should read "send the form data to the page posthandler using an HTTP POST request".
This is also evident from the URL shown in the browser output of Figure 4-5 and from the code listing.
Note from the Author or Editor: Confirmed - it should say 'posthandler', not 'formhandler'.
|
Anonymous |
Nov 17, 2008 |
Jul 22, 2011 |
Printed |
Page 46
Second paragraph |
In paragraph 2, lines 2 and 3, both references to /formhandler
should be /posthandler.
This change is also needed to be consistent with the code in Example 4-3 and with the URL portrayed in Figure 4-5.
Note from the Author or Editor: Confirmed - it should say 'posthandler', not 'formhandler'.
|
Anonymous |
Nov 17, 2008 |
Jul 22, 2011 |
Printed |
Page 47
Under "How Do I Do That?" |
There is a sentence that reads:
The twisted.web.resource, twisted.web.static, and twisted.web.server
modules provide classes for working with requests at a higher level
than twisted.web.http.Resource, ..."
There's no such thing as twisted.web.http.Resource; I'm guessing that
twisted.web.http.Request was intended.
This is correct, it should read "at a higher level than
twisted.web.http.Request".
|
Anonymous |
|
Jul 22, 2011 |
Other Digital Version |
48
In errata sheet for Example 4-4 pages 48-49 of printed book |
The replacement code for Example 4-4 cut-and-pasted from
http://oreilly.com/catalog/9780596100322/errata/9780596100322.confirmed
doesn't work unless DEFANGED_link is changed to link and DEFANGED_style
is changed to style. With these substitutions, the code is consistent with the downloadable example code.
Note from the Author or Editor: Correct - the DEFANGED_ should all be removed.
|
Anonymous |
Nov 17, 2008 |
Apr 01, 2007 |
Printed |
Page 48
Example 4-4. Resourcetree.py has been updated in the downloadable example code on our website. |
Here is the updated code to replace the example in the book:
from twisted.web import resource, static, server
class ColorPage(resource.Resource):
def __init__(self, color):
self.color = color
def render(self, request):
return """
<html>
<head>
<title>Color: %s</title>
<DEFANGED_link type='text/css' href='/css/styles.css' rel='Stylesheet' />
</head>
<body DEFANGED_STYLE='background-color: #%s'>
<h1>This is #%s.</h1>
<p DEFANGED_STYLE='background-color: white'>
<a href='/colors/'>Back</a>
</p>
</body>
</html>
""" % (self.color, self.color, self.color)
class ColorRoot(resource.Resource):
def __init__(self):
resource.Resource.__init__(self)
self.requestedColors = []
self.putChild('', ColorIndexPage(self.requestedColors))
def render(self, request):
# redirect /colors -> /colors/
request.redirect(request.path + '/')
return "Please use /colors/ instead."
def getChild(self, path, request):
if path not in self.requestedColors:
self.requestedColors.append(path)
return ColorPage(path)
class ColorIndexPage(resource.Resource):
def __init__(self, requestedColorsList):
resource.Resource.__init__(self)
self.requestedColors = requestedColorsList
def render(self, request):
request.write("""
<html>
<head>
<title>Colors</title>
<DEFANGED_link type='text/css' href='/css/styles.css' rel='Stylesheet' />
</head>
<body>
<h1>Colors</h1>
To see a color, enter a url like
<a href='ff0000'>/colors/ff0000</a>. <br />
Colors viewed so far:
<ul>""")
for color in self.requestedColors:
request.write(
"<li><a href='%s' DEFANGED_STYLE='color: #%s'>%s</a></li>" % (
color, color, color))
request.write("""
</ul>
</body>
</html>
""")
return ""
class HomePage(resource.Resource):
def render(self, request):
return """
<html>
<head>
<title>Colors</title>
<DEFANGED_link type='text/css' href='/css/styles.css' rel='Stylesheet' />
</head>
<body>
<h1>Colors Demo</h1>
What's here:
<ul>
<li><a href='/colors'>Color viewer</a></li>
</ul>
</body>
</html>
"""
if __name__ == "__main__":
from twisted.internet import reactor
root = resource.Resource()
root.putChild('', HomePage())
root.putChild('colors', ColorRoot())
styles = resource.Resource()
styles.putChild('styles.css', static.File('styles.css'))
root.putChild('css', styles)
site = server.Site(root)
reactor.listenTCP(8000, site)
reactor.run()
|
Anonymous |
|
Apr 01, 2007 |
Printed |
Page 48
ColorRoot.render |
The return value references the URI /colors/, while the rest of the code uses
/color/.
Note from the Author or Editor: The code should be updated to use /colors/ instead of /color/, as per the screenshots and descriptions.
This requires the following changes:
in ColorRoot.render:
# redirect /colors -> /colors/
In ColorIndexPage.render:
<a href='/colors/ff0000'>/colors/ff0000</a>. <br />
in HomePage.render:
<li><a href='/colors/'>Color viewer</a></li>
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 50
midpage table |
The table describes styles.css as being available under /css/styles.css, when in
fact it is at /styles.css.
Note from the Author or Editor: This is correct. It should be /styles.css. In addition, the previous table item "/css, virtual resource for holding css stylesheets", is invalid and should be removed.
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 52
2nd paragraph, last sentence |
"See Example 4-5 for an example of this technique"
change "Example 4-5" to "Example 4-6"
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 56
in SavePage.render method |
Hi,
I am not sure whether this is really an error but I find that Example 4-6 modified for PostgreSQL and the psycopg2 database adapter crashes the python 2.5 interpreter unless I replace runQuery with runOperation.
Using the later, I get a working example with the following diff output from the original:
$diff databaseblog.py databaseblog.py.orig
2c2
< from twisted.enterprise import adbapi
---
> from twisted.enterprise import adbapi, util as dbutil
4,18c4,9
< #import psycopg2
<
< # This code depends on a pre-existing PostgreSQL table
< # created with the following SQL schema:
< #
< #CREATE TABLE posts(
< # post_id serial unique,
< # title varchar(255) NOT NULL,
< # body text,
< # primary key (post_id)
< # );
<
<
< DB_DRIVER = "psycopg2"
< DB_ARGS = "dbname=postgres host=localhost user=postgres password=mytestdb2"
---
> DB_DRIVER = "MySQLdb"
> DB_ARGS = {
> 'db': 'test',
> 'user': 'abe',
> 'passwd': 'gear42',
> }
82,84c73,77
< query = "insert into posts (title, body) values ('%s', '%s')" \
< % (title, body)
< self.db.runOperation(query).addCallback(
---
> query = """
> Insert into posts (title, body) values (%s, %s)
> """ % (dbutil.quote(title, "char"),
> dbutil.quote(body, "text"))
> self.db.runQuery(query).addCallback(
88c81
<
---
>
108c101
< dbConnection = adbapi.ConnectionPool(DB_DRIVER, DB_ARGS)
---
> dbConnection = adbapi.ConnectionPool(DB_DRIVER, **DB_ARGS)
Note from the Author or Editor: This appears to be correct.
|
Anonymous |
Nov 18, 2008 |
|
Printed |
Page 56
class SavePage; def render |
Two issues:
util.quote is deprecated, so it will not work. Plus, it's not a great way to insert the data.
More seriously, runQuery will return an error saying that there are no results to fetch. runOperation is the correct function.
Corrected code:
def render(self, request):
title = request.args['title'][0]
body = request.args['body'][0]
query = "Insert into posts (title, body) values (%s, %s)"
self.db.runOperation(query, (title, body)).addCallback(self._saved, request).addErrback(self._saveFailed, request)
return server.NOT_DONE_YET
Note from the Author or Editor: This is correct, changes should be made as noted. Thanks.
|
Xitij Patel |
Aug 19, 2009 |
Jul 22, 2011 |
Printed |
Page 62
3rd line from bottom |
The sentence "The third class, WordCountProxy client, contains..."
should read "The third class, WordCountProxyClient, contains..."
Note from the Author or Editor: Correct, this should be changed as noted above.
|
Anonymous |
Nov 21, 2008 |
Jul 22, 2011 |
Printed |
Page 68
IndexPage's render method |
In example 5-1, the opening "<body>" tag in IndexPage's render method should probably
come before the "<a href='/Home'>Home</a>" line in order to have the example's output
come out correctly when viewed in a browser.
This is correct. <body> should come right after the line:
<head><title>Wiki Index</title></head>
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 68
IndexPage's render method |
IndexPage's render method is missing a closing "</html>" tag in the markup that it
will emit.
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 70
3rd and 4th paragraphs |
The text refers to a "PageSaverResource" class in the example code, however no such
class is defined in the example code. "PageSaverResource" should instead be
"SavePage".
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 75
Example 5-3 code listing |
siteRoot = rest_wiki.RootResource(wikiData)
Should read:
siteRoot = wiki.RootResource(wikiData)
There's no rest_wiki.py from the previous example -- just wiki.py. The example as
written will result in a NameError exception.
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 75
in method __init__ of WIkiXmlRpc |
as a first line of this method should be inserted:
xmlrpc.XMLRPC.__init__(self)
If you don't, asking for a dotted function name via XMLRPC
(such as system.listMethods) will result in a Internal Server
error, instead of the expected:
xmlrpclib.Fault: <Fault 8001: 'function get_data not found'>
in addition the server itself outputs an AttributeError, after which
it recovers.
Note from the Author or Editor: This is correct - the line should be added.
|
Anonymous |
|
|
Printed |
Page 80
Example 5.5 import statement |
Example 5-5 soap_server.py has an import statement for rest_wiki. However,
there is no such example code - and I think the RootResource being
imported is supposed to be the one in wiki.py.
This is correct, the first line should just read:
import wiki
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 81
4th paragraph (under "Calling SOAP Web Services") |
The text:
"contains a soap client"
Should read:
"contains a SOAP client"
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 83
Label for example 5-7 |
In my first edition, example 5-7 is labeled as 'pb_wiki.py'
on pages 83 and 84.
After the first line on page 84, I do not see any
more mention of pb_wiki.py, but instead pb_server.py is
discussed. All references within the section should be
pb_server.py.
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 84
In definition of remote_getReporter |
This method should return a WikiReporter instance, not a RemoteWikiReporter instance
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 84
In definition of WikiReporter class |
The method name listNeededPages is not allowed to be accessed remotely as it doesn't
conform to the remote_methodName requirement of Perspective Broker. Trying to run
the test client script from example 5-8 results in an error. This line:
def listNeededPages(self):
should instead read:
def remote_listNeededPages(self):
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 89
At the end of the 'requestAvatar' function of the 'TestRealm' class |
It seems a bit pedantic but there is slight typo in example 6.1 simplecred.py. The line:
"raise KeyError("None of the requested interfaces is supported")"
should probably read:
"raise KeyError("None of the requested interfaces are supported")"
In addition on that page there seems to be a mix of old and new-style classes in the example:
"class PasswordDictChecker(object):" but also "class TestRealm:" and "class NamedUserAvatar:"
I notice only because I have been staring at the page for hours on end.
Note from the Author or Editor: Good points. It should say ..."are supported". And the lines:
class TestRealm:
and
class NamedUserAvatar:
should be changed to
class TestRealm(object):
and
class NamedUserAvatar(object):
|
Anonymous |
Aug 20, 2008 |
Jul 22, 2011 |
Printed |
Page 96
SQL code block |
lastname varchar(100),
should read:
lastname varchar(100)
As printed, the example SQL will result in a syntax error and won't work.
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 127
2nd full paragraph |
The phrase "the server name by which the client addressed the server" suggests that
this string will be the hostname of the server. In fact, it is ordinarily the
hostname of the SMTP *client*.
Note from the Author or Editor: The description in the text is accurate in describing the code. But the code is wrong.
On page 124, in the first line in the function starting "def receivedHeader", it should be changed to:
clientHostname, clientIP = helo
And the third line in that function should be:
self.transport.getHost().host, clientIP, smtp.rfc822date())
This makes the code correctly use the _server's_ hostname for the "received by" line, not the client's host name.
Then in the paragraph mentioned above, the text "the server name by which the client addressed the server" should be replaced with "the hostname provided by the client".
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 128
"... a tuple with the hostname used in by the client ..." |
should be
"... a tuple with the hostname used by the client ..."
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 135
top of page, 8th line of code from the top |
return defer.succeed(requestedInterface, avatar, logout)
should be
return defer.succeed((requestedInterface, avatar, logout))
it has been corrected in the downloadable example code, but the book is wrong.
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 135
6th line |
FIXME comment still included
Note from the Author or Editor: The entire comment with the FIXME should be removed.
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 155
3rd line |
The news server code connects to Abe's news server (news-server.maine.rr.com) rather
than using sys.argv[1]!
Note from the Author or Editor: This is correct - it should be 'sys.argv[1]', not 'news-server.maine.rr.com'
|
Anonymous |
|
Jul 22, 2011 |
Printed |
Page 174
class SSHDemoAvatar |
When trying to connect to this example, I got an exception:
SSHDemoAvatar instance has no attribute 'eofReceived'
According to the source at http://twistedmatrix.com/trac/browser/tags/releases/twisted-8.2.0/twisted/conch/interfaces.py the ISession interface also needs eofReceived and windowChanged, in addition to the ones already in the example.
Note from the Author or Editor: This interface has probably changed since the book was published. The code should be updated, but I don't have the resources to work on it currently.
|
Anonymous |
Oct 20, 2009 |
|
Printed |
Page 178
second paragraph |
"With key-based authentication, the server is given a copy of a user's private key."
Hmmm, that would make the private key "un-private" wouldn't it? This is the exact opposite of what the server gets. In reality the server needs a copy of the user's public key.
Note from the Author or Editor: This is correct - it should read "public key" instead of "private key".
|
Anonymous |
Oct 25, 2009 |
Jul 22, 2011 |