By Developers, For Developers

Historical errata for Code in the Cloud

PDF PgPaper PgTypeDescriptionFixed onComments
77ERROR

Incorrect code sample shown for method ChatRoomCountedHandler.

The code does not contain the loop to calculate the timedelta field as referenced in the following text.

2010-04-04
83TYPO

2nd para. Sentence starting “In the next chapter…” missing word “to” at end of 4th line (after “how”).

Same sentence, line 6, word “sour” should be “our”

2010-03-31
46ERROR

textarea tags in file chattwo.py don’t render in browser when using self closing tags ie. <textarea ….. />
Should us <textarea …>

2010-03-31Strange... Works for me in both Safari and Chrome. But I've modified the code so that it should work for you now.
53ERROR

codeblock for retrieving persistent objects.

lines 5-9 should not be there (they are a variation of lines 1-4 but with a limit clause in)

2010-03-31Thanks; accidentally reused a metadata label, so it added both code fragments.
57ERROR

codeblock for retrieving persistent objects.
line 1 the order clause should be “order by timestamp” and not “order by time”

2010-03-31
59ERROR

line 12 of the code block the order clause should be “order by timestamp” and not "order by time

2010-03-31
68TYPO

last paragraph:
The idea behind the use of templaces
should be
The idea behind the use of templates

2010-03-31
65TYPO

in line 24 of code block

Enter new message from: " %s
The single quotation mark doesn’t make sense (doesn’t result in error) but looks like a typo

2010-03-31
71ERROR

line 8 the order clause should be “order by timestamp” and not “order by time”

2010-03-31
69TYPO

lines 6-8 in the code block are rendering part of your internal markup showing {#} at the end of the lines where they are numbered for reference

2010-04-03I think this is fixed; it's messy, because I get different results in my local build versus the online build, and the template is an overlap between two different languages with two different comment syntaxes.
71ERROR

error in downloadable code of codeblock at (media.pragprog.com/titles/mcappe/code/template-chat/tchat.py) missing http call at front of url as this wont allow me to post a url

this downloadable code is missing the following import statements:

import os
from google.appengine.ext.webapp import template

2010-04-03
50ERROR

Link to Wikipedia article on HTTP is incorrect

2010-03-31
56TYPO

2nd para references to “time” property should be to “timestamp” property

2010-03-31
57ERROR

last line of page “ORDER BY time” should be “ORDER BY timestamp”

2010-03-31
59ERROR

I go the following error when running sample code:

‘GqlQuery’ object has no attribute ‘reverse’

I deleted the line messages.reverse() and changed the for loop to:

for msg in reversed(list(messages)):

2010-04-03Things in AppEngine change too fast! Thanks for catching that.
61TYPO

Missing comma at end of 2nd line of code, after

(‘/talk’, ChatRoomPoster)

2010-03-31
13TYPO

2nd paragraph, line 6, “VAX 11/780, named nicknamed” should be “VAX 11/780 named” or “VAX 11/780 nicknamed”.

2010-04-19Thanks! I have no idea how many times I've ready that section without noticing that.
24SUGGEST

In the gray aside box, the author states, “I’ll say more about this later, but I’m not a huge Python fan.”

The Python sections of this book are why I bought it. So, my initial reaction to this comment was a feeling that I had wasted my money, and I nearly put the book down.

I feel if the author doesn’t like Python, how can I possibly expect quality coverage of it? I would recommend removing such personal commentary from the final product since Python coverage may be the sole reason a reader, such as myself, bought your book.

2010-04-27I've toned it down a bit. But I'd be lying if I said that I love Python, or that I think it's the best way of building programs in AppEngine. But that doesn't mean that I'm not going to cover it thoroughly or fairly. In fact, I think that it's really unreasonable to expect that only a person who is a huge fan of Python can possibly write a quality text using Python. \n \nHonestly, given my choice, I wouldn't be writing in Python *or* Java. But the point of the book isn't "Here's how to write cloud applications in my favorite programming language". It's "Here's how to write cloud applications". \n \nOne of the things that makes this book - and prag books in general - special is that the authors have very distinct voices and opinions, and those are reflected in the books. The book definitely reflects my opinions, and I think that taking them out would make the book much less valuable. But you'll still get your moneys worth even if your opinions don't match with mine. \n
21TYPO

“Create at Application” instead of “Create an Application”:

When you have the tools you need to write Python programs, you can
download the AppEngine Python SDK by logging into the AppEngine
account you created in the previous section, and clicking “Create at
Application.”

2010-04-27
24TYPO

“configures application” instead of “configures applications” or “configures your application”?

appcfg.py uploads and configures application using AppEngine in
the cloud.

2010-04-27
25TYPO

“nderstand” instead of “understand”

When
we get to GWT, it will be easy to nderstand what’s really going
on.

2010-04-27
74TYPO

“an consistent” instead of “a consistent”

you provide the user with the feeling that they’re using an
consistent, well-designed application.

2010-04-27
71SUGGEST

Your templates contain “{#}” but you don’t explain it.

I guess they’re django comment tags. I suggest adding some comment text, deleting the empty comment tags or explaining the comment tag.

2010-04-27Those are typesetting artifacts which we're working on correcting. They're fragments left from the markup that generates the callout numbers. The typesetting code that we use doesn't yet support Django comments correctly, so those are left in the typeset results. I'm aware of them, and they'll eventually be fixed, when the prag hamsters have time.
106TYPO

“user as on actions” instead of “user actions”

With JavaScript, you can embed programs in your application’s pages
that respond to user as on actions.

2010-04-27
106TYPO

“as a object” instead of “as an object”

Second, your JavaScript program can manipulate the entire HTML page,
or any portion of it, as a object,

2010-04-27
115TYPO

“sent a XML document” instead of “send an XML document”

We’ll just sent a XML
document

2010-04-27
139TYPO

“It’s as full-featured” instead of “It isn’t as full-featured”

It’s as full-featured as our
Python chat application yet, but it’s got a better UI,

2010-04-27
160TYPO

“60emss” instead of “60ems”

We set its width to 60emss,
and it’s height to 20ems.

2010-04-27
179TYPO

“users first connects” instead of “users first connect”

When users first connects to a chatroom,

2010-04-27
187TYPO

“strangeness” instead of “strangenesses” (or is that too strange?)

here are
a few of the most common strangeness

2010-04-27
78TYPO

The “ChatRoomCountedHandler” class in the code listing should be named “ChatRoomCountViewPage” to be consistent with the example in the previous chapter

2010-06-02This isn't a typo - it's just a change in naming as the code gets more complex. That's deliberate: my experience is that people often start off very rough and fuzzy, and then as they progress, things become more robust -both in terms of functionality, and in terms of stylistic things like naming. \n
16TYPO

Second paragraph, last sentence: “You can build anything as a service in the cloud, but it might be a lot harder that developing it as a standalone application.”

Suppose it should be: “…a lot harder than developing…”

2010-08-16
30TYPO

Last sentence on page 30 reads: For this, we’re using two basic webapp building blocks: the webapp module itself, and a a webapp function called run_wsgi_app.

“and a a webapp” should be “and a webapp”

2010-08-16
47TYPO

7th paragraph reads: To implement in AppEngine, we need to build a RequestHander

Should be “RequestHandler”

2010-08-16
48ERROR

Code on page 48 is correct, but the download file chattwo.py has an error in this line:

2010-08-16
29TYPO

Command sample (middle of page): “$ appcfg.py update chat”

The running example is using a directory name of ‘chatone’ but the command uses ‘chat’. If this is correct, it is (at least) not clear how the author gets from one to another.

2010-08-17
31TYPO

Item #7 - second sentence:

The function called is listed as “run_wsgiapplication”. It should be “run_wsgi_app”.

2010-08-16
31SUGGEST

Item #7 - First sentence: “…makes use of a common Google idiom.”

One could argue that it is in fact a Python idiom. At least even I have seen it used in the regular Python documentation (and tutorials).

2010-08-16
58TYPO

Second paragraph: This text and the following code snippets uses ‘time’ for the property called ‘timestamp’ in the ChatMessage class. Coding while following the text then returns no chat entries in the GQL queries because of the ‘ORDER BY time’ clause.

2010-08-16
63TYPO

Download file ‘persist-chat/pchat.py’ contains no definition for class ChatRoomTimeViewPage, but instead a duplicate implementation of ChatRoomCountViewPage.

2010-08-17
230ERROR

Graf says:
“The time parameter basically says, “Please keep this in memory for at least this long.” There’s no guarantee it will stay stored for that long …"

I interpret the docs to mean “keep it at most this long,” which the next sentence implies as well.

AppEngine docs say:
“time
Optional expiration time, either relative number of seconds from current time (up to 1 month), or an absolute Unix epoch time. By default, items never expire, though items may be evicted due to memory pressure. Float values will be rounded up to the nearest whole second.”

2010-08-16
60TYPO

the query should be “… order by timestamp” the text shows just “time”

2011-01-09
64TYPO

Missing a comma on second continuation line:
chatapp = webapp.WSGIApplication([(‘/’, ChatRoomPage), (‘/talk’, ChatRoomPoster)
(‘/limited/count’, ChatRoomCountViewPage), (‘/limited/time’, ChatRoomTimeViewPage)])

2011-01-09
62TYPO

In the persist-chat/pchat.py example, the source code for the first change is truncated with the text “…TRUNC”.

2011-01-09
45TYPO

The text in bullet #1 should read “…method for the request, followed BY the URL of the resource..”. The word “by” is missing.

2011-01-09
63TYPO

Using a bound parameter in the LIMIT clause is producing the error “Non-number limit in LIMIT clause”. According to AppEngine issue #179, bound parameters are not supported in LIMIT and OFFSET clauses. Unfortunately I can’t include a link to the issue entry on the AppEngine Google code website. Standard Python string substitution appears to work OK.

2011-01-09Grumble - this worked when I wrote the chapter. Unfortunately, things keep changing; this, however, is the first time I recall a change that reduced a useful and simple function. \n
18ERROR

“you can run your application in EC2 using Linux, Solaris, AIX, or Windows Server” - I don’t believe AIX is available. AIX runs on Power RISC processors, not on Intel.

2011-01-09
32SUGGEST

Item 7 - “The rest of the file makes use of a common Google idiom” - wasn’t this a common Python idiom, long before Google existed?

2011-01-09There are a few different idioms that are used for things like this in Python. This is the particular one that we follow at Google. I don't think it's incorrect to say it's the Google idiom - it's the one that we use. \n
47TYPO

“4. Four indicates a client error (for example, 401 means that the client requested a resource which doesn’t exist on the server).” - “401” should be “404”.

2011-01-09
49SUGGEST

Where you have

I suggest you should have

2011-02-02
49SUGGEST

Your submit button is labelled “Send ChatMessage” - but ChatMessage is the name of an implementation class; I don’t think it’s intended to be part of the user’s conceptual model of the application. “Send Message”, or just “Send”, would be better. I know this is a small point, but things like this distract readers.

2011-01-09The user is in a chat room, sending chat messages. I don't think that there's anything unclear about saying "send chat message" versus "send message". It's a matter of taste which you prefer. \n
58SUGGEST

Somewhere in this discussion of the datastore you need to show the import required, e.g.
from google.appengine.ext import webapp, db

2011-01-30
68TYPO

Near the bottom of the page, the line of code containing “Enter new message from: %s” is missing closing b and p tags.

2011-01-30
69SUGGEST

The reader also needs to know the additional import needed:
from google.appengine.api import users

2011-01-30
64SUGGEST

“We don’t yet have a nice way of moving between the views, and their implementations have a silly amount of duplication. We’ll look at how to clean that up in the next chapter—but for now, we’ve got something that works.” - In fact, the next chapter looks at authentication. I’d prefer it if you did clean things up before going on to a different topic.

2011-02-02
49ERROR

In the listing on this page user-provided data is being sent to the browser without HTML escaping. This makes it easy for users to break the application and opens up the possibility of XSS attacks. Using
import cgi
…
self.response.out.write("

%s

" % cgi.escape(str(msg)))
would fix this.

2011-01-09This is deliberate; I use it as an example of a common error later on, in the security chapter, by pointing out that that the way we implemented the code here leaves it open to an XSS attack. \n
66SUGGEST

I think you should point out that applications hosted on Google App Engine can use whatever authentication and authorisation mechanisms they like - it isn’t necessary for users to have Google accounts to log in to GAE apps, if the app implements some other authentication mechanism. It’s just really convenient if the users do have Google accounts.

2011-01-09
72SUGGEST

You can improve the formatting of the message timestamp and escape the user-provided message content using filters:

{{ m.user }} ( {{ m.timestamp|date:“F j Y H:i” }} ): {{ m.message|escape }}

2011-01-09Yes, I could - but it just adds a bit more noise and complexity to the code. The point of the code here is to be as clear and focused as possible: to show what's essential. Adding extra template format controls just isn't necessary. I can't cover every feature of the template system - that would be an entire book of its own. So I'd prefer to keep it as simple as possible, and try to focus on GAE. The Django template docs are pretty good, and if people are writing apps using them, they'll need to read the Django manuals. \n
74SUGGEST

Imports again:
import os
from google.appengine.ext.webapp import template
BUT although the documentation (e.g. appengine/docs/python/gettingstarted/templates.html) shows the ugly FILE path based technique, there’s a tip on that page saying:
Tip: An App Engine application has read-only access to all of the files uploaded with the project, the library modules, and no other files. The current working directory is the application root directory, so the path to index.html is simply “index.html”.
So in fact we don’t need the import of ‘os’, or the line building the path - we can just use:
page = template.render(‘chat-template.html’, template_values)

2011-01-30
94TYPO

Half way down the page (in reason 2): “when we change the way that we write them in XML, we won’t need to change our CSS” - “XML” should be “HTML”.

2011-01-09
118TYPO

Second line on page: “Now we’re going to implement to controller.” - “to controller” should be “the controller”.

2011-01-09
68TYPO

The code downloaded from this page (login-chat/pchat.py) make reference to ChatRoomTimeViewPage and ChatRoomCountViewPage, but these classes are not in the file downloaded. Also the code still has “ORDER BY time” where the model defines it as timestamp

2011-01-30
128TYPO

The file generated by Eclipse for HelloChat.gwt.xml doesn’t contain a doctype declaration

2011-01-30That's peculiar. The file that's used to generate that piece of the book was generated by Eclipse, and when I try it even in a newer version of Eclipse, I still get the doctype declaration. \n
129TYPO

The HelloChat.html has the doctype <!doctype html> For standards mode and html5 compatibility

2011-01-09
16TYPO

in “The computer may not have be sitting on” … “not have be” should be:

not have to be

2011-01-09Fixed; actually, though, it should read "not be". \n
18TYPO

“Before we start actually writing programs, we’ll take a quick look at a few examples, to give you a sense of what the options.”

should be something more along the following:

Before we start actually writing programs, we’ll take a quick look at a few examples to give you a sense of the options available.

2011-01-09
23TYPO

“But for a cloup app” cloup should be cloud

2011-01-09
63TYPO

When adding the time-limited view

ChatMessage.gql(“WHERE timestamp > :fiveago ORDER BY time”, fiveago=datetime.now() - timedelta(minutes=5)).

Should be “timestamp” after ORDER BY

(Actually, learning how to correct this is a good way to dig into Python and appengine logs)

2011-01-30
86TYPO

In the multichat app , the landing page is not described. The chat.html template is neither described nor provided in the source files.

chatapp = webapp.WSGIApplication([(‘/’ , ChatRoomLandingPage),
(‘/talk’ , ChatRoomPoster),
(‘/enterchat’ , GenericChatPage)])

2011-01-30
127TYPO

On my setup (Eclipse Helios / appenfine 1.4.0) the GreetingServiceImpl.java file is part of the server package, not the client one. The third flie of the client package is GreetingServiceAsync.java

“The client side has a three files. One of them, HelloChat.java is the main body of our application. The other two, GreetingService.java and GreetingServiceImpl.
java are part of the setup for a GWT remote procedure call.”

2011-01-30
78TYPO

In the code for the master.html template, there is a loop that prints

  • elements for the primary navigation section.

    Within that loop, the line that prints the actual link has the following code:

  • c.name

  • This line should have the chat name in curly brackets, like so:

  • {{ c.name }}

  • 71SUGGEST

    Authentication description is very limited in the book and adds little value to what is available in google’s own “getting started” tutorial

    Some insight about how to authenticate using an alternative provider (facebook, openid) and how to glue it all together would be very valuable.

    60TYPO

    Section: Retrieving Persistent Objects
    The GQL query should be … ORDER BY timestamp (not time)

    64TYPO

    Line 2 should be DATETIME.datetime.now() - DATETIME.timedelta(minutes=5)
    and the GQL query should be WHERE timestamp > :fiveago ORDERED BY TIMESTAMP", fiveago=DATETIME.datetime.now() - DATETIME.timedelta(minutes=5))

    (dont forget to change the gql query on line 13 and 14)

    66TYPO

    line 10: … to use USE GAE’s login service. (one use too much?)

    69TYPO

    The indentation level of the first if statement in the post method is wrong. But it’s correct in the pchat.py source file.

    69TYPO

    I’m sorry. The indentation of the first if statement in the post method in the pchat.py source file is wrong too.

    69TYPO

    post method:
    the local variable user is read before assignment. move the 3rd line (user = users.get …) to the top of the post methods body

    82SUGGEST

    I tried to run the source code from chapter 6 and got the following error:

    no matching index found.
    This query needs this index:
    - kind: ChatMessage
    properties:
    - name: chat
    - name: timestamp

    I’m new to GAE so this error message didn’t help me much, at first. It took me some time to figure it out.
    I also got an error message related to the chat field, which was introduced to the model on page 82.
    I think it would help many readers new to GAE who are following the steps mentioned in the book to build the chat application, if you would mention the index.yaml file and its purpose.
    I found the solution to those problems, when I downloaded the code shipped with the book.

    128TYPO

    4th paragraph:
    GreetingServiceImpl.java is not in the client package, it’s in the server package.
    I think you mean that GreetingServiceAsync.java is in the client package.

    137TYPO

    2) The service interface declaration must extend >>T<<he GWT interface

    158TYPO

    Is the bottomPanel a HorizontalPanel or a VerticalPanel.
    In the source code bottomPanel is a HorizontalPanel, but in the description it is a VerticalPanel

    159TYPO

    Does the title label get the style apptitle or title?
    In the source code (p. 158) it gets title.

    159TYPO

    “(There is a setStyle name, but …” <- setStyleName not setStyle name

    159TYPO

    (3)
    In the code above, we called addStyle to alter the appearance <- addStyleName

    170SUGGEST

    11.6 The GWT Widget Gallery. . .

    I think it’s best to provide a link to the newest WidgetGallery.

    …/webtoolkit/doc/1.6/RefWidgetGallery.html <- change 1.6 to latest

    171TYPO

    We’ll examine WE else we need in our server

    32TYPO

    ‘debugging’ -> ‘debugger’

    94ERROR

    The closing body tag

    is in the wrong place. In the document, it has been placed within the closing div tag for the content div.

    Move the closing body tag to the line before the closing html tag.

    166TYPO

    / Fired when the user types in the nameField. */
    “nameField” should be “messageBox”

    62ERROR

    The author has chosen not to display the Import statements as he modifies the code going from oen chapter to the next and that means those lines are missing when I write the code myself and so my code errors out when run. I have to search online for the right imports (e.g., “from google.appengine.api import users” and “import sys” for this User login chapter) and then my code works. This is not ideal, IMO.

    63ERROR

    In the “post” code for the login-chat example, these two lines are shown in the wrong order so the program errors until these lines are swapped:

    1. START: PostHandler
      def post(self):
      if user is None:
      self.redirect(users.create_login_url(self.request.uri))
      user = users.get_current_user()

    You can’t say “if user is None” unless you’ve tried to instantiate “user” first.

    63ERROR

    In the post method, the ChatMessage should be passed the variable “nick” instead of “user.nickname()” since the previous lines of code check for an undefined user.nickname().

    In other words…

    msg = ChatMessage(user=user.nickname(), message=msgtext)

    should be:

    msg = ChatMessage(user=nick, message=msgtext)

    Note: Since the book requires Python 2.5, you could also shorten the code for the nickname to use the ternary in Python 2.5 and up:

    so…

    if user.nickname() is None or user.nickname() == “”:
    nick = “No Nickname”
    else:
    nick = user.nickname()

    becomes…

    nick = “No Nickname” if (user.nickname() is None or user.nickname == “”) else user.nickname()

    63ERROR

    In the post method, the ChatMessage should be passed the variable “nick” instead of “user.nickname()” since the previous lines of code check for an undefined user.nickname().

    In other words…

    msg = ChatMessage(user=user.nickname(), message=msgtext)

    should be:

    msg = ChatMessage(user=nick, message=msgtext)

    Note: Since the book requires Python 2.5, you could also shorten the code for the nickname to use the ternary in Python 2.5 and up:

    so…

    if user.nickname() is None or user.nickname() == “”:
    nick = “No Nickname”
    else:
    nick = user.nickname()

    becomes…

    nick = “No Nickname” if (user.nickname() is None or user.nickname() == “”) else user.nickname()

    70ERROR

    Downloaded both the template-chat files, and the multi-chat files. Can’t seem to get either of them to work. Am getting a “raise BadValueError(’Property s is required’ self.name) BadValueError: Property chat is required” … Any ideas?

    70TYPO

    Downloaded both the template-chat files, and the multi-chat files. Can’t seem to get either of them to work. Am getting a “raise BadValueError(’Property s is required’ self.name) BadValueError: Property chat is required” … Any ideas?

    SOLVED - Had been using chatone all the way through on dev_appserver.py and had just been updating the app.yaml page to point to a new python file with each new exercise.

    Typing “dev_appserver.py —clear_datastore chatone” in terminal fixed my problems above.

    Categories: