Errata

Twisted Network Programming Essentials

Errata for Twisted Network Programming Essentials

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.

The following errata were submitted by our customers and have not yet been approved or disproved by the author or editor. They solely represent the opinion of the customer.

Color Key: Serious technical mistake Minor technical mistake Language or formatting error Typo Question Note Update

Version Location Description Submitted by Date submitted
PDF

example code:
h = HeadlineRetriever()
d = h.getHeadline("1234567890" * 6)
d.addCallbacks(printData, printError)

raise TypeError("Strings are not supported by Failure")

John Santiago Jr.  Aug 24, 2014 
Printed, PDF 113, 114

In page 114, paragraph "Before writing this test case..." is redundant and confusing.

In the code example at 113 the reactor is already parameterized.
I think one of them should go. Either code example or paragraph.

Anton Antonov  Jan 24, 2015 
PDF Page 17
Example 2-4. quoteclient.py

Should the QuoteProtocol class be derived from protocol.ClientProtocol instead of the protocol.Protocol?

Tom Trop  Apr 08, 2014 
PDF Page 19
Item 3 in the list

3. Clients can make make many simultaneous connections to a server.

SHOULD BE CHANGED TO:

3. Clients can make many simultaneous connections to a server.

David Z. Han  Mar 28, 2014 
PDF Page 19
First line

In the echo server

SHOULD BE CHANGED TO:

In the quote server

David Z. Han  Mar 28, 2014 
27
Example 3-2

Example 3-2 demonstrates calling an errback with a string argument (Python type str). This is no longer supported in Twisted as of September 2012: http://twistedmatrix.com/pipermail/twisted-commits/2012-September/036016.html. Running the code verbatim raises an "exceptions.TypeError: Strings are not supported by Failure". Failure expects an Exception or a subclass thereof.

This error affects Example 3-2, and all subsequent examples that call addErrback with a string argument.

Example 3-2 would run if the last line was replaced with:

d.errback(Exception("Triggering errback"))

Garrett Robinson  May 21, 2013 
PDF Page 27
1st example

example call:

d.errback("Triggering errback.")


produces an unexpected error:

File "/usr/local/lib/python2.7/dist-packages/twisted/python/failure.py", line 204, in __init__
raise TypeError("Strings are not supported by Failure")
TypeError: Strings are not supported by Failure

Alex Karpov  Jun 30, 2013 
Printed Page 27
Example 3-2 Using addErrback

To generate the correct error message used in Example 3-2, the program should be changed to the following:

from twisted.internet.defer import Deferred
from twisted.python.failure import DefaultException

def myErrback(failure):
print failure

d = Deferred()
d.addErrback(myErrback)
d.errback(DefaultException("Triggering errback."))

When the above is run, it will generate the error message listed for Example 3-2:

[Failure instance: Traceback (failure with no frames): <class 'twisted.python.failure.DefaultException'>: Triggering errback.
]

Thomas R. Stevenson  Oct 04, 2015 
PDF Page 28
Near middle of page

In the sentence "Example 3-4 retrieves a headline ... or printing an error to stderr if ...", stderr should be stdout, because the printError() function (on the next page) simply calls "print failure", which goes to stdout.

Tom Trop  Apr 09, 2014 
PDF Page 34
Fig. 3-3

The example is meatn to illustrate the behaviour of addCallbacks (plural), but the text says:

addCallback(myCallback, myErrback)

Alex Karpov  Jun 30, 2013 
PDF Page 34
First line in Figure 3-3

addCallback(myCallback, myErrback)

SHOULD BE CHANGED TO:

addCallbacks(myCallback, myErrback)

David Z. Han  Mar 28, 2014 
PDF, ePub Page 34
Figure 3-3

The text in the image:

"addCallback(myCallback, myErrback)"

should be:

"addCallbacks(myCallback, myErrback)"

Zoltan Benedek  Nov 19, 2014 
PDF, ePub Page 43, 46
2nd paragraph

PDF:

On page 43:
"requestFactory instance variable"

should be:
"requestFactory class variable"

On page 46:
"isLeaf instance variable"

should be:
"isLeaf class variable"

Zoltan Benedek  Nov 26, 2014 
PDF Page 43
2nd paragraph after the code sample

Typo: "MyRequestHander" supposedly means "MyRequestHandler"

Tibor Simon  May 03, 2016 
PDF Page 47
Line 13 from the bottom

an instance of twisted.web.error.NoResource

SHOULD BE CHANGED TO:

an instance of twisted.web.resource.NoResource

David Z. Han  Mar 28, 2014 
PDF Page 53
Last line of code Example 5-1. print_resource.py

Example code 5-1 print_resource.py is calling 'exit(1)'. Because it is importing 'sys' the call to 'exit()' should be prefixed by system module. like 'sys.exit(1)'.

Current example:

```
import sys

# Some code

if len(sys.argv) != 2:
print("...")
exit(1)
```


Expected correction:

```
import sys

# Some code

if len(sys.argv) != 2:
print("...")
sys.exit(1)
```

Jaysinh Shukla  May 10, 2018 
PDF Page 54
Second line in section Downloading a Web Resource

getPage

SHOULD BE CHANGED TO:

downloadPage

David Z. Han  Mar 28, 2014 
PDF Page 59
Line 7: print statement

post_resource.py

SHOULD BE CHANGED TO:

post_data.py

David Z. Han  Mar 28, 2014 
PDF Page 59
middle of page starting at ``class ResourcePrinter``

Looks like ``class ResourcePrinter`` and beyond is indented into the body of the ``StringProducer`` class.

Chapman  Apr 04, 2014 
Printed Page 193
Example Code multiservice.py

Due to the change from python2 -> python3, strings are handled differently, which makes it necessary to encode and decode back and forth to feed twisted bytestrings where necessary.

It took some time and python knowledge to get the mutliservice.py example code to run on recent Python (3.9.2)


Hopefully this helps anyone who is as hooked on that piece of code as I am.


>>>>>>>> multiservice.py <<<<<<<<<<<

from twisted.application import service, internet
from twisted.internet import protocol, reactor, defer
from twisted.protocols import basic
from twisted.web import resource, server as webserver

class Reverser:
def __init__(self):
self.history = []

def reverse(self, string):
self.history.append(string)
reversed = string[::-1]
return reversed

class ReverserLineProtocol(basic.LineReceiver):
def lineReceived(self, line):
if line == b'quit':
self.handle_quit()
else:
#l = self.factory.reverser.reverse(line)
l = line.decode('utf-8')
rev = self.factory.reverser.reverse(l)
self.sendLine(rev.encode('utf-8'))

def handle_quit(self):
self.transport.loseConnection()

class ReverserLineFactory(protocol.ServerFactory):
protocol = ReverserLineProtocol

def __init__(self, reverser):
self.reverser = reverser

class ReverserPage(resource.Resource):
def __init__(self, reverser):
self.reverser = reverser

def render(self, request):
if b"string" in request.args.keys():
#if request.args.has_key("string"):
string = request.args[b"string"][0]
s = string.decode('utf-8')
reversed = self.reverser.reverse(s)
else:
reversed = ""

html = """
<html><body><form>
<input type='text' name='string' value='%s' />
<input type='submit' value='Go' />
<h2>Previous Strings</h2>
<ul>
%s
</ul>
</form></body></html>
""" % (reversed,
"\n".join(["<li>%s</li>" % s for s in self.reverser.history]))

return html.encode('utf-8')

class ServiceAdminPage(resource.Resource):
def __init__(self, app):
self.app = app

def render_GET(self, request):
request.write(b"""
<html><body>
<h1>Current Services</h1>
<form method='post'>
<ul>
""")
for srv in service.IServiceCollection(self.app):
if srv.running:
checked = "checked='checked'"
else:
checked = ""
services = """
<input type='checkbox' %s name='service' value='%s'>%s<br />
""" % (checked, srv.name, srv.name)
request.write(services.encode('utf-8'))
request.write(b"""
<input type='submit' value='Go' />
</form>
</body></html>
""")
return b''

def render_POST(self, request):
actions = []
#serviceList = request.args.get(b'service', [])
serviceList = [ x.decode('utf-8') for x in request.args.get(b'service', []) ]
#print("[DBG] service: " + serviceList)
print(serviceList) # TODO: this seems to be empty regardless of what it is called with
for srv in service.IServiceCollection(self.app):
if srv.running and not srv.name in serviceList:
stopping = defer.maybeDeferred(srv.stopService)
actions.append(stopping)
elif not srv.running and srv.name in serviceList:
# wouldn't work if this program were using reserved ports
# and running under an unprivileged user id
starting = defer.maybeDeferred(srv.startService)
actions.append(starting)
defer.DeferredList(actions).addCallback(
self._finishedActions, request)
return webserver.NOT_DONE_YET

def _finishedActions(self, results, request):
request.redirect('/')
request.finish()

application = service.Application("Reverser")
reverser = Reverser()

lineService = internet.TCPServer(2323, ReverserLineFactory(reverser))
lineService.setName("Telnet")
lineService.setServiceParent(application)

webRoot = resource.Resource()
webRoot.putChild(b'', ReverserPage(reverser))
webService = internet.TCPServer(8000, webserver.Site(webRoot))
webService.setName("Web")
webService.setServiceParent(application)

webAdminRoot = resource.Resource()
webAdminRoot.putChild(b'', ServiceAdminPage(application))
webAdminService = internet.TCPServer(8001, webserver.Site(webAdminRoot))
webAdminService.setName("WebAdmin")
webAdminService.setServiceParent(application)


Anonymous  Apr 04, 2021