Go To Homepage



Book Details
The Definitive Guide to Pylons book cover
  • By James Gardner
  • ISBN13: 978-1-59059-934-1
  • ISBN10: 1-59059-934-9
  • 568 pp.
  • Published Dec 2008
  • Print Book Price: $46.99
  • eBook Price: $32.89



Errata Submission

If you think that you've found an error in The Definitive Guide to Pylons, please let us know about it. You will find any confirmed erratum below, so you can check if your concern has already been addressed.

Submit Errata
The Definitive Guide to Pylons (978-1-59059-934-1)

Errata

Issue Author's Response
Ch. 6 Pp. 116-123
I think that you misunderstood the errata that I originally submitted.

class Study is originally defined with an attribute named people then without explanation this is renamed to person.

What I was trying to point out was that on page 116, the Study class has an attribute incorrectly named 'people'. After this, every definition of the Study class names the attribute 'person'.
Ah, yes sorry. It should be person in the initial instance. You are right. Thanks for taking the time to point out the mistake.
Chapter 6. (Do not know the page, it the HTML)
The first line in lines below misses the colon.

class Study(Schema)
pre_validators = [NestedVariables()]
title = String(not_empty=True)
...
Thanks, there is indeed a missing semi-colon.
Chapter 18, url: http://pylonsbook.com/en/1.1/authentication-and-authorization.html#authkit

More clarification than errata, but I thought others might find it helpful:

"To implement a facility for signing out, you will need to add this line to your config file:

authkit.cookie.signoutpath = /auth/signout
"

It seems to me that a brief warning example regarding the interaction of routes and h.url_for() with
authkit.cookie.signoutpath would be very helpful. You added a warning and I heeded it, but I didn't quite understand what I was looking for. Example: If i have a route for some variable pageid, and signout() is in the page controller, then the following does *not* work if pageid is set:

${h.url_for(controller='page', action='signout')}

since h.url_for automatically adds pageid, whereas the following gives the correct url:

${h.url_for(controller='page', action='signout', pageid=None)}
Yes, the URL that routes generates for the sign out URL must be the same as the one you've specified for AuthKit in the config file. That sometimes means you have to be quite careful about setting up the correct route. Thanks for clarifying here for others.
Chapt. 3, page 34. This isn't an error, but I think that you have to specify better of what debug options you are speaking. Because, if I understand well, the debug option in [DEFAULT] sets to true permit you to obtain the traceback of some error via email, so should be set to true also in production. Whereas the debug option in [app:main] controls the interactive debug and have to be set to false in production. NO. PLEASE NEVER HAVE debug=True IN PRODUCTION.

The debug option controls whether tracebacks are displayed in the browser or sent via email.

Leaving true on for production is a huge security risk as explained in the book. Hope that's clearer now.

Thanks, James
http://pylonsbook.com/en/1.0/working-with-forms-and-validators.html
Chapter 6,
Section "Using HTML Fill"
"or the open source Nvu program based on Mozilla project code"

It seems that this should now read "open source KompoZer program". From their website (http://kompozer.net/about.php):

Why call it «KompoZer» instead of «Nvu»?

Because « Nvu and the Nvu logo are trademarks of Linspire Inc. »
As Linspire stopped the development of Nvu, there is no legal way to correct any bug in Nvu.
Thanks for the tip but I wouldn't consider this an errata point. If I ever write an updated version of the book I'll make the change.
Ch. 6 Pp. 116-119
class Study is originally defined with an attribute named people then without explanation this is renamed to person.
No, Study and Person are different classes. A Study has many people which are instances of the Person class.
CH 14 p 287 Changes to edit() method.
Add before return the line
'c.comment = comment'
because the edit.html contains 'id=c.comment.id' in the call to url_for().
I don't think this is correct. Looking at the code examples for Chapter 14 which accompany the book, the template/derived/comment/edit.html file does not contain c.comment.id, it contains request.urlvars['id'].
ch 14, p281,
AS IS request.params.get
TO BE page_q.params.get
No. It should be request.params.get as written because the ID comes from the URL. The page_q object does not have a .params attribute anyway.
Ch. 21, pg. 499
I followed your instructions to deploy using an Apache webserver and then spent a long time trying to understand why logging didn't work as I expected. It turns out that to set up the logging config, you need to add the following to the <app>.wsgi file:

fileConfig(<your .ini file>)

see http://wiki.pylonshq.com/display/pylonscookbook/Logging+under+mod_wsgi
I believe this is only the case if you don't configure logging to log to wsgi.errors as described in page 479. I'll add a note to the online version with your solution though. Thanks for the catch.
chapt. 7 page 148

schema.Column('posted', types.DateTime(), default=now),
should be
schema.Column('posted', types.DateTime(), default=now()),
No, it should be now so that the time is recorded when SQLAlchemy creates the page, otherwise all the pages will have the same value.
chapt. 9 page 201,202
In the last map.connect example you use action='list' (pag. 201), but in the last map.match example (pag. 202) you print {'action': u'aggregate',.....
Thank you, yes, it should be 'list'.
Ch. 14 pg. 286
I think that you also need to mention that pageid=c.page.id needs to be passed as the first arg for each h.url_for call in list.html
I think it is only one instance which needs changing on p284 which has already been noted. Thanks for reporting it though.
Chapter on Forms, page 113, the code:

def submit(self):
# Imagine we have a connection object now:
c.connection = connection
schema = EmailForm(state=c)
... same as before


I've tried this example. From what I can tell (and on IRC), you can't pass the c object to the form like this. I could not get this to work on my 0.9.7 release. Is this a bug or something from a prior release?
There is no problem with using the c object like this in simple cases as long as you create a new instance of the schema *on each request* so that the c object from one request doesn't get confused with the c from another. In this example the EmailForm instance is created *inside* an action so it will be created on each request. FormEncode will sometimes add attributes to the state itself but this usually doesn't cause a problem.

Of course if you want to be 100% correct you can always create your own state object with the database connection if you prefer.
Chapter 8
p. 183
in def edit(...), data is stored in page, I think it should be c.page
p. 184
in edit.html, title is referenced as c.title, I think it should be c.page.title
The problem is only obvious if running with strict_c = True (in which case it crashes!)
p183: No, I think it is correct to store it in page. The values from the page object are used in values.

p184: Let's just specify c.title = page.title at the end of the edit() function to avoid the change having other side-effects.
CH 7, page 149

comment table created column has "default=now()"
This is meta-data creation time. For comment record creation time, change to "default=now".
Well spotted, thank you.
CH6, P 125
May I know if the FormExample been tested on IE 7?

It is running fine with Firefox but no response on IE7 submission.
It wasn't tested on IE7, I only run Linux. If you could provide a fix I'd be happy to change the text?

Thanks, James
(I'm reading the online version, so I don't have a page number.)

Chapter 3, "Understanding Pylons Globals". There is a block of sample code that reads:

import helloworld.lib.helpers as h
from helloworld.lib import app_globals
from pylons import config

The second line has to be changed to:
from pylons import app_globals

As currently written, global variables are not properly instantiated. I'm not one to bash an excellent, freely available resource, but I spent a few hours spinning my wheels on this one. :-)

Also, a bit further down, the section entitled "App Global Object" reads, in part:

"Here is a simple counter example that demonstrates how the app_globals object works. First modify your lib/app_globals.py Globals class so that the __init__.py method looks like this:"

This should be corrected to:

"Here is a simple counter example that demonstrates how the app_globals object works. First modify your lib/app_globals.py Globals class so that the __init__ method looks like this:"

(Notice the lack of ".py" on the __init__ method)
Yes, both these changes are correct. Thanks for reporting them and sorry they wasted your time.
Ch2, beginning of section "Quick start to installation for the impatient" :
AS IS: "3. Windows users would use Scripts instead of bin in the above command ..."
TO BO: "3. Windows users would use Scripts instead of bin in the below command ..."
Quite right, this is fixed online. Thanks.
chapter 6 says:

"""
To override the default value for an error message, you pass a msgs argument to the validator’s constuctor. For example:

name = String(msgs={'empty':'Please enter a name'})
"""

The actual argument name is 'messages' not 'msgs' (at least in FormEncode 1.2.1)
OK, thank you.
chp6,page120:
% if c.email_msg:
<span class="error-message">${c.email_msg}</span><br />
% endif
E-mail Address: ${h.text('email', value=c.email_value)}
but youe shoud set:
config['pylons.strict_tmpl_context'] = False
in enviroment.py,if not config this content, when view url http://127.0.0.1/formtest/form,it raise error.
True, but this book is for 0.9.7 where config['pylons.strict_tmpl_context'] is False anyway so this shouldn't be a problem. You could always change the code to set a default value of c.email_value = '' if you prefer, right at the top of the submit() function. Thanks.
Chapter 18, pg 420

The paragraph below the definition for the sign out action states

"...you can test the sign-out process by visiting http://localhost:5000/hello/signout.".

I think this should read "http://localhost:5000/auth/signout", at least I hope I've understood this right.
Spot on, thank you.
Hi,

From the on-line version, chapter 5 Basic Template Syntax section:

If you’d like to follow along with any of the examples in this section, create a new template called basic.html, and then create a new action in the controller to render it, because you will return to the greeting.html example later in the chapter so shouldn’t change that template now.


Maybe break that into two sentences:

... action in the controller to render it. Because you will return to the greeting.html example later in the chapter you shouldn't change that template now.
Agreed. Thanks.
Chapter 6
Page 105

Second code error in 'simpleform.html' example. You have two closing form tags, one created with ${h.end_form()} and a second standard </form> tag. Am assuming the second shouldn't have appeared.
Quite right, thank you.
Chapter 6
Page 105

Code example error

The following line of code in the example is wrong:

return 'Invalid: 'unicode(error)

It should read either

return 'Invalid: ', unicode(error)
or
return 'Invalid: '+unicode(error)

Either of which will concatenate the two string into a single which will return.
Thanks, let's go with:

return 'Invalid: '+unicode(error)

(This is actually already fixed online)
Chapter 15, page 343.
You say that in javascript every object passed into functions is passed by reference. I tried the sample code and it didn't work. I searched the internet and found this:
http://snook.ca/archives/javascript/javascript_pass
This says that, indeed, every object is passed by reference, but also that every primite type, like numbers and strings, is passed by value.
That's true too but I'm not sure it is very relevant because you can't change the value of primitive types anyway. As I say in the text the behaviour is just like Python. Here's the Python equivalent of that example:

def myfunction(x):
# x is equal to 4
x = 5
# x is now equal to 5

x = 4
print x # x is equal to 4
myfunction(x)
print x # x is still equal to 4
Online edition, Chapter 14, Setting the Page ID Automatically

http://pylonsbook.com/en/1.0/simplesite-tutorial-part-2.html#setting-the-page-id-automatically

The "no comments" link in comment/list.html needs updating to pass in the page id:

Change this line:

<a href="${h.url_for(controller='comment', action='new')}">Add one</a>.

to this line:

<a href="${h.url_for(pageid=c.page.id, controller='comment', action='new')}">Add one</a>.
Yes, that's correct, thanks.
Ch. 14, pg. 309 - Indentation in 'def delete' method is all over the place and definitely is not working as is. (insert whitespace based language flame here) Indeed it is, thanks. Refer to the online version for correct indentation: http://pylonsbook.com/en/1.0/simplesite-tutorial-part-2.html#creating-the-controllers
CH 17 P 286.

AS IS :

Let's consider each of the actions ...

TO BE (suggestion) :

You'll also need to make similar changes to the list.html template.

Let's consider each of the actions ...
=====
This is in Chapter 14 actually. I think it is only one instance which needs changing on p284 which has already been noted. Thanks for reporting it though.
Chapter 8: Creating the Model

"Change model.__init__.py to look like this:"

shouldn't it be:

"Change model/__init__.py to look like this:"
Yes it should, thanks. This is already fixed in the online version.
Chapter 14, Simple-Site-Tut Part 2
In the definition in templates/component/navigation.html, render_list is defined as render_list(items, current, id, class_), but is called with 5 arguments, including type_. Adding this to the parameter list solves the error
Yes, quite right. It is missing type_ as the third argument before id. Thank you.
CH 12 P 260
The value of response.status is '302 Found'.
AS IS assert response.status == 302
TO BE assert response.status_int == 302
No, that's not correct because in Pylons 0.9.7 (which the book describes) the response object is the old Paste one, not the new WebOb (Pylons) one so the .status attribute is an integer. For later versions of Pylons your change may well be correct though.
Chapter 6: Creating the Form

In the complete code for the study.py controller it imports the following on line 12:

from formencode.validators import Int, DateConverter, String, one of

Shouldn't it be:

from formencode.validators import Int, DateConverter, String, OneOf
Yes it should, thank you.
Chapter 3, page 48

the code:
import helloworld.lib.helpers as h

and

h.url_for(...) # somewhere in the controller

does not work, providing the following traceback:
AttributeError: 'module' object has no attribute 'url_for'
That's right, thanks, you also need to import url_for into lib/helpers.py. I'll change the online text to read like this:

One of the most useful helpers is ``h.url_for()``, which is a function that comes from the Routes package to help you generate URLs. To use this helper you should add the import below to your project's ``lib/helpers.py`` file:

::

from routes import url_for
CH 11 P 239
I was careful to follow the exercise exactly as in the book. The add_fallback('es') simply does not work. The language does not fall back to 'es'.

I also tried to remove __before__()code and did this
def index0(self):
add_fallback('es')
set_lang('fr')
return _('Goodbye!')
and it still does not fall back to Spanish, but the Spanish text is there when I do set_lang('es').
You are right, I can't get it to work now either. Perhaps this is a Pylons bug?? If you know a workaround please let me know.
Chapter 19, page 436.
In the first paragraph, change the table name "user_roles" to "users_roles".
Yes, well spotted, thank you. Although I might add that my preference now is for singular table names so I wouldn't necessarily recommend the naming convention AuthKit happens to use as a good guide for other tables.
Chapter 18, page 425.
In the last code listing, change "import HasAuthKitRole, HasAuthKitRole," to "import HasAuthKitRole, HasAuthKitGroup,".
Yes, thank you, that's correct.
Chapter 18, page 423.
The last two code examples contain incorrect indentation, which is important for Python code.

The following lines need indentation:
response.status = "401 Not authenticated"
return "You are not authenticated!"

and

from authkit.permissions import NotAuthenticatedError


In addition, the code to raise the NotAuthenticatedError is missing.
Yes, that's correct, thanks. This is already fixed in the online version.
Chapter 10, page 223.
After the 2nd paragraph, the coding for the Mako template file should be changed from "## -- coding: utf-8 --" to "## -*- coding: utf-8 -*-".
Yes it should, thank you.
Chapter 9, page 209.
In the last code example, the first 2 commands should use the input values '/blog/view/1/' and '/blog/view/1' instead of '/blog/view/4/' and '/blog/view/4'.
Well spotted, thank you.
Chapter 9, page 207.
In the last paragraph, changing the wording from "need to specify routing variables, which are different from the ones matched" to "need to specify the routing variables that are different from the ones matched" would be clearer.
Agreed, thank you.
Chapter 9, page 204.

In the diagram definition of the parts of a URL, the 'http' part is labeled "protocol". Although it appears that the Routes request_config object uses the attribute name "protocol", WebOb.request uses the name "scheme" to access the WSGI url_scheme value.

I think it is more common for developers to interact with the WebOb "scheme" than the Routes "protocol", so I believe that this deserves at least a Tip, if not changing the diagram label to use "scheme". This could help developers search for the proper documentation in the related modules/libraries.
I agree. I'll change it to 'scheme' online. Thanks.
Chapter 9, page 201.
In the 2nd to last paragraph, change "so their default values of 'archives' and 'list' will always be used" to "so their default values of 'page' and 'list' will always be used".
Yes, that's correct. Thank you.
CH 8 P 183 function edit()
AS IS
...
}
return htmlfill.render...

TOBE
...
}
c.title = page.title
return htmlfill.render...
Yes, that's right. Thanks.
Chapter 5: Structuring Template Code: Namespaces:

Error - extra characters in line 9 of the first code example:

" ( not )'James','http://jimmyg.org')"

should be

" ('James','http://jimmyg.org'),"
Yes, thank you, Apress clearly misunderstood what I'd written when I was trying to correct a bracket which was the wrong way around!
CH 7, P 140
AS IS : print "Column Table name: ", column.type
TO BE : print "Column: ", column.type
in order to produce the output given a few lines later in the text.
Yes, that's correct too, "Column Table name: " should read "Column: ".

Thanks!
ch 7, p 139
Missing ':'
AS IS for t in metadata.sorted_tables
TO BE for t in metadata.sorted_tables:
=====
That's right, the example is missing a colon at the end of the first line.
Chapter 18

[start quote]

$ easy_install "AuthKit>=0.4.3,<=0.4.99"
$ paster create --template=pylons AuthDemo
$ cd AuthDemo
$ paster serve --reload development.ini

To set up the authentication middleware, edit the AuthTest project’s config/middleware.py file, and add the following import at the end of the existing imports at the top of the file:

[end quote]

As noted above, the project was created and named 'AuthDemo'.
(Example: $ paster create --template=pylons AuthDemo )

However on the subsequent line, the project was referred to as 'AuthTest'.
(Example: ... middleware, edit the AuthTest project’s ... )

This error could cause confusion to readers.
You are quite right, the line just before the import on page 418 should read AuthDemo not AuthTest. Thanks.
Chapter 2, page 15, "Here's how it looks on Windows:..." with Python26 gives a stack trace with "ImportError: No module named _socket".
Probably obvious to an experienced user.
The I have file C:\Python26\libs\_socket.lib
Here are the relevant env vars.
PYTHONPATH=C:\Python26\Lib;C:\Python26\libs
Path=C:\WINDOWS\system32;C:\WINDOWS;C:\Python26;C:\Python26\libs
Somehow, it does not find _socket.
I'm afraid I'm not a Windows user so I can't test this problem. I did test Python 2.5.2 though on Vista when I wrote the book and that worked perfectly so can I suggest you use Python 2.5 instead? There may still be some problems with Pylons on Python 2.6 generally so I'd currently recommend Python 2.5 for all users anyway.
chapt. 8, page 172:

model.__init__.py does not have the sm = orm..... line when generated. The notes imply that this line should be changed for SA 0.5, since Pylons generates for SA 0.4. The comments on the page don't indicate that this is a manual modification.

Higher on the page, #Add these two imports..... lines do indicate that manual modification is done.

Should Pylons generate the sm = orm........... line? Is this a generator bug, or a doc ambiguity?
The book was written against Pylons 0.9.7rc2. The actual release of Pylons 0.9.7 uses SQLAlchemy 0.5 by default so text in Chapter 8 about how to upgrade a project to SQLAlchemy 0.5 is no longer relevant.

In Pylons 0.9.7 the sessionmaker() call is still made, but it happens in your project's model/meta.py file instead of model/__init__.py

If you leave the model.init_model() function and the model/meta.py package exactly as Pylons now generates them I believe everything else should still work.

You still need the two imports at the top of page 172 though.
page 136: after some hours of web searching, I found the answer, and not on the Postgres site, either. Seems that PG uses %s as parameter marker. Made that change. Might be worth mentioning in the text that not all databases follow the odbc/jdbc convention. Sorry that caused confusion. I've added an explanation to the previous errata submission.

Thanks for pointing out the problem!
page 136:
The insert statement doesn't run against Postgres 8.3.6 on Ubuntu 8.10/64 sqlalchemy 0.5.3. This syntax does work ->
connection.execute(
"""
insert into users (username, password) values ('foo', 'bar');
"""
)

Also, none of the SQLAlchemy docs I could find use the """ syntax. I couldn't find an explanation of why """ is useful. Yes, I am new to Python, too.
Different databases use different markers (known as param styles) to label where the variables you pass to execute() should be inserted. The example above used SQLite which uses ? as the param style but if you use MySQL or PostgreSQL you would need to use %s as the param style instead. The SQL would then look like this:

connection.execute(
"""
INSERT INTO users (username, password) VALUES (%s, %s);
""",
"foo", "bar"
)

Using """ characters to mark the begining and end of the SQL allows you to use " and ' characters as part of the SQL and also allows you to add line breaks if your SQL statements get very long.
Chapter 6, page number 117,123, action 'Remove'

In base/index.html you iterate: for id in range(c.number_of_people). In most cases you will hit an ID, that might be removed by action 'Remove'
You are quite right. I believe the code at the bottom of page 123 should in fact look like this:

elif action.startswith('Remove'):
# Get the ID of the set of person fields to remove
id = int(action.split(' ')[-1])
# Create a new set of values without those fields
new_values = {}
for k, v in values.items():
name, field = k.split('.')
cur_id = int(name[len('person')+1:])
if cur_id<id:
new_values[k] = v
elif cur_id>id:
new_values['person-%s.%s'%(cur_id-1, field)] = v
# Render the form with the new values
return render_form(
values=new_values,
number_of_people = number_of_people(new_values)
)

Thanks for the catch.
Chapter 5, page 70, I could not get the example working.
Error !
AttributeError: 'module' object has no attribute 'url_for'
13 <p>
14 <p>Hello ${c.name}! You are visiting ${h.url_for()}</p>
15

Please contact me to explain how to get this working.
thanks,
Greg
Hi Greg,

You need to import the url_for() helper. The instructions for how to do this are in the very next line of the book. Edit templatedemo/lib/helpers.py and add this import:

from routes import url_for

Hope you get it working,

Cheers,

James
Chapter 6, page 105, syntax error in the submit example
return 'Invalid: 'unicode(error)

should be
return 'Invalid: ',unicode(error)
or
return 'Invalid: '+unicode(error)
That's right, it is missing the + operator. It should read:

return 'Invalid: '+unicode(error)

(using a , wouldn't work correctly incidentally)

Thanks.
Chapter 6, page 102 the last line of the simpleform.html (</form>) shouldn't be there That's right, the tag is generated by h.end_form(). Thanks.
Chapter 6, page 97 wrong link to pylons documentation
no "http://docs.pylonshq.com/thirdparty/webhelpers/html/html.html#webhelpers-html-tags"
but "http://pylonshq.com/docs/en/0.9.7/thirdparty/webhelpers/"
The correct links should be:

http://docs.pylonshq.com/thirdparty/webhelpers/html/html/#webhelpers-html-tags

Thanks.
Chapter 6, page 96, wrong redirect link
"the browser redirects to http://localhost:5000/hello/result"
should be
"the browser redirects to http://localhost:5000/formtest/result"
Yes, you are quite right. Thank you.
Chapter 5, page 75, section "Applying Filters to Templates", typo error:
"apply filers to specific Mako"
should be
"apply filters to specific Mako"
Correct, the word "filters" is missing the letter "t". Thanks.
The documentation page for pylons 0.9.7 was changed so every reference to the old one was wrong. E.g. in Chapter 3, page 47 and Chapter 3, page 52 the link http://docs.pylonshq.com should be http://pylonshq.com/docs/en/0.9.7 True, but the URLs in the book work too so I wouldn't consider this a big problem. The documentation URL might even change again at some point in the future but I'd hope we'd keep the correct redirects working.
Chapter 5, page 75
based on the example code "return HTML.span(HTML.em(value), id='first', class_='highlight')" the representation of the Unicode string should be <span id='first' and not <span id="id"
In Chapter 5, page 75, second to last paragraph before the Applying Filters in Templates section the code <span id='id' should read <span id="first"