I guess we all agree that CherryPy needs an easy way to fully
customize error pages.
The original poster of ticket 800 (schap...@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:
# 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.
Nicolas Grilly wrote: > I guess we all agree that CherryPy needs an easy way to fully > customize error pages.
> The original poster of ticket 800 (schap...@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:
> # 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 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].
> I guess we all agree that CherryPy needs an easy way to fully > customize error pages.
> The original poster of ticket 800 (schap...@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:
> # 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.
Robert Brewer <fuman...@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'].
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.
Robert Brewer <fuman...@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?
Nicolas Grilly wrote: > Robert Brewer <fuman...@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?
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 <fuman...@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?
> Nicolas Grilly wrote: > > Robert Brewer <fuman...@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?
> 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.
> 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 :-)
>> 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 :-)
Following Robert's comment: Great work. This is one of the features people will immediately enjoy :)