Follow-up on ticket 800 (Request ability to override default error template)

17 views
Skip to first unread message

Nicolas Grilly

unread,
Apr 21, 2008, 4:04:14 PM4/21/08
to cherrypy-devel
Hello,

I guess we all agree that CherryPy needs an easy way to fully
customize error pages.

The original poster of ticket 800 (scha...@mischko.com) proposed a
patch, but Robert considered it messy. I agree, especially because of
the use of "exec" to import a module, when error_page is a string
ending by ".py"... However, I think this patch contains one very
useful idea we should keep: the ability to configure "error_page.0" to
have a default error page used for every HTTP error codes.

Later, Robert proposed another patch, where the error_page related to
each code can be a template filename or a callable. This API seems
better than the previous one. But Robert was uncomfortable with the
patch because it left too much work in the callable (set the status,
call clean_headers, etc.).

So, here is another proposition mixing previous ones:

"error_page.<code>" can be a template filename or a callable. Filename
works as with current version of CherryPy. Callable receives the
arguments prepared by get_error_page (status, message, version,
traceback...) as keyword parameters and must return a string
representing the HTML response document.

"error_page.0" can be used to specify a default error page, valid for
all HTTP error codes.

To implement this into trunk, only one change is needed into function
cherrypy._cperror.get_error_page, by replacing those lines:

template = _HTTPErrorTemplate
...
return template % kwargs

by these lines:

# Use a custom template for the error page?
error_page = cherrypy.request.error_page.get(code) or
cherrypy.request.error_page.get(0)
if error_page:
try:
if callable(error_page):
return error_page(**kwargs)
else:
return file(error_page, 'rb').read() % kwargs
except:
e = _format_exception(*_exc_info())[-1]
m = kwargs['message']
if m:
m += "<br />"
m += "In addition, the custom error page failed:\n<br />
%s" % e
kwargs['message'] = m

return _HTTPErrorTemplate % kwargs

Benefits of this solution are:
- Only one change into get_error_page
- Backward compatible with current version of CherryPy
- Possible to completely customize the error page by using a callable
(you can use your favorite templating engine)
- The callable must only return an HTML page; the dirty work is made
by get_error_page and HTTPError.set_reponse (set the status, call
clean_headers, build the default message corresponding to the status
code, etc.)
- Possible to define one default error page instead of one error page
for each HTTP error code

If you think this solution is adequate, I volunteer to write the few
lines of code needed and the unit tests.

Thanks,

Nicolas

Robert Brewer

unread,
Apr 21, 2008, 4:26:53 PM4/21/08
to cherryp...@googlegroups.com

Thanks for the thought and effort on this--it'd be really nice to
resolve for 3.1 final. I'd like to pursue the idea of requiring an
error_page callable to return HTML (but possibly do other things)...have
a look at the branch I made for ticket 800 and see if you can modify it
to do what you described.

I'm still pretty adamantly opposed to using 0 as a magic number to mean
'default'. IMO that sort of information-encoding is a holdover from C
and similar languages where 1) your identifiers need to fit in a CPU
register and 2) static typing promotes shoving out-of-band information
into a struct it was never designed for. In other words, I'd rather see
a new "error_page_default" attribute, or even error_page['default'],
than error_page[0].


Robert Brewer
fuma...@aminus.org


braydon fuller

unread,
Apr 21, 2008, 5:01:52 PM4/21/08
to cherryp...@googlegroups.com
I have also made a patch. Here I am able to send a complete html page
rather than a message:
http://groups.google.com/group/cherrypy-devel/browse_frm/thread/7ab58f345d8e650c

You send the whole page as "body", similar as sending a "message":

def foobar(uri):
try:
location = get_uri(uri)
data = get_data(location)
success = Template(file=filename, searchList=[data])
except:
error = Template(file=filename, searchList=[locals()])
raise HTTPError(404, body=error)
foobar.exposed = True

Nicolas Grilly

unread,
Apr 21, 2008, 7:50:40 PM4/21/08
to cherryp...@googlegroups.com
Robert Brewer <fuma...@aminus.org> wrote:
> Thanks for the thought and effort on this--it'd be really nice to
> resolve for 3.1 final. I'd like to pursue the idea of requiring an
> error_page callable to return HTML (but possibly do other things)...have
> a look at the branch I made for ticket 800 and see if you can modify it
> to do what you described.

OK. I'll look at the branch and propose a patch ASAP.

> I'm still pretty adamantly opposed to using 0 as a magic number to mean
> 'default'. IMO that sort of information-encoding is a holdover from C
> and similar languages where 1) your identifiers need to fit in a CPU
> register and 2) static typing promotes shoving out-of-band information
> into a struct it was never designed for. In other words, I'd rather see
> a new "error_page_default" attribute, or even error_page['default'],
> than error_page[0].

I completely agree with that: I'm going to use error_page['default'].

Thanks,

Nicolas

Nicolas Grilly

unread,
Apr 21, 2008, 8:40:08 PM4/21/08
to cherryp...@googlegroups.com
braydon fuller <cou...@braydon.com> wrote:
> I have also made a patch. Here I am able to send a complete html page
> rather than a message:
> http://groups.google.com/group/cherrypy-devel/browse_frm/thread/7ab58f345d8e650c
>
> You send the whole page as "body", similar as sending a "message":
>
> def foobar(uri):
> try:
> location = get_uri(uri)
> data = get_data(location)
> success = Template(file=filename, searchList=[data])
> except:
> error = Template(file=filename, searchList=[locals()])
> raise HTTPError(404, body=error)
> foobar.exposed = True

Braydon,

It seems your patch doesn't solve the same kind of problem.

Ticket #800 is about providing a way to customize the error page
returned by default by every HTTPError.

But your proposal, if I understand it well, is about adding a
parameter "body" to HTTPError, in order to customize the error page
returned by a specific instance of HTTPError.

If I am correct, we probably should discuss this in a dedicated
thread, with a descriptive title.

Nicolas Grilly

unread,
Apr 21, 2008, 10:13:14 PM4/21/08
to cherryp...@googlegroups.com
Robert Brewer <fuma...@aminus.org> wrote:
> Thanks for the thought and effort on this--it'd be really nice to
> resolve for 3.1 final. I'd like to pursue the idea of requiring an
> error_page callable to return HTML (but possibly do other things)...have
> a look at the branch I made for ticket 800 and see if you can modify it
> to do what you described.

Here is the patch I promised some hours ago. Of course, I've updated
related docstrings and unit tests. I hope it can help solve the ticket
#800.

As I am sending this patch, I think the "callable" should be
authorized to return document types outside of HTML. This is useful
for some kind of servers, like XML-RPC. What do you think about that?

ticket_800_ngrilly.patch

Robert Brewer

unread,
Apr 22, 2008, 3:24:08 AM4/22/08
to cherryp...@googlegroups.com

Of course. We wouldn't want the overhead of validating HTML anyway. ;)
The callable can set any Content-Type it likes, and whatever it returns
gets bound to cherrypy.response.body.


Robert Brewer
fuma...@aminus.org

Nicolas Grilly

unread,
Apr 22, 2008, 9:27:32 AM4/22/08
to cherryp...@googlegroups.com
Robert Brewer <fuma...@aminus.org> wrote:
> Of course. We wouldn't want the overhead of validating HTML anyway. ;)
> The callable can set any Content-Type it likes, and whatever it returns
> gets bound to cherrypy.response.body.

Do you want me resending the patch with updated stringdocs for
inclusion into SVN?

Robert Brewer

unread,
Apr 26, 2008, 7:10:47 PM4/26/08
to cherryp...@googlegroups.com

Okay, trunked in http://www.cherrypy.org/changeset/1949. Thanks for the
work!

Just to make things clearer for myself, I also added a slick new chart
to http://www.cherrypy.org/wiki/ErrorsAndExceptions. It sure helped me
decide to favor Nicolas' patch over my own. ;)


Robert Brewer
fuma...@aminus.org

Nicolas Grilly

unread,
Apr 29, 2008, 10:59:41 AM4/29/08
to cherryp...@googlegroups.com
Robert Brewer <fuma...@aminus.org> wrote:
> Okay, trunked in http://www.cherrypy.org/changeset/1949. Thanks for the
> work!
>
> Just to make things clearer for myself, I also added a slick new chart
> to http://www.cherrypy.org/wiki/ErrorsAndExceptions. It sure helped me
> decide to favor Nicolas' patch over my own. ;)

Thanks Robert!

I'm happy to give back something useful to CherryPy :-)

Sylvain Hellegouarch

unread,
Apr 29, 2008, 11:03:13 AM4/29/08
to cherryp...@googlegroups.com

Following Robert's comment: Great work. This is one of the features people
will immediately enjoy :)

- Sylvain

>
> >


--
Sylvain Hellegouarch
http://www.defuze.org

Reply all
Reply to author
Forward
0 new messages