{"id":2890,"date":"2017-10-24T14:43:55","date_gmt":"2017-10-24T12:43:55","guid":{"rendered":"http:\/\/blog.gocept.com\/?p=2890"},"modified":"2018-01-17T10:23:10","modified_gmt":"2018-01-17T09:23:10","slug":"zope4-errorhandling","status":"publish","type":"post","link":"https:\/\/blog.gocept.com\/2017\/10\/24\/zope4-errorhandling\/","title":{"rendered":"Catching and rendering exceptions"},"content":{"rendered":"
TL;DR:<\/strong> You have to write an exception view in file system code which is rendered when an exception occurs.<\/p>\n If an exception occurred in Zope 2 the When using a WSGI server on Zope 2 the Thats why error handling changed again in Zope 4: \u00a0Like Zope 3 (aka BlueBream)\u00a0Zope 4\u00a0tries to lookup an exception view if an exception occurs. If the lookup succeeds (aka there is an exception view registered for the current exception) this view is rendered as response. This approach allows different views for different exceptions. The\u00a0 <\/p>\n The exception view has to be created in the file system and registered via ZCML. If you do not have a file system package yet \u2013 where this code can be placed \u2013 you can create a new package e. g. by using Where In the existing\u00a0 This view returns the string The view gets registered for\u00a0 If you put these files into a Zope Product they could be picked automatically. If you created an\u00a0 After re-starting Zope each exception renders as Writing HTML in a Python class is not very convenient. It is easier to use a PageTemplate to store the templating code. Create a file In\u00a0 If you have an existing The code in the example expects that\u00a0 Zope 4 has a nice and flexible concept to render error pages. But it requires at least some Python code in the file system. Even this can be tricked back to Error handling in Zope 4<\/p>\n","protected":false},"author":15344399,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_newsletter_tier_id":0,"footnotes":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[10221],"tags":[196,832,6,72208,594099838],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pFP3y-KC","jetpack-related-posts":[{"id":2789,"url":"https:\/\/blog.gocept.com\/2017\/10\/25\/testing-zope-4beta2\/","url_meta":{"origin":2890,"position":0},"title":"Migrating from Zope 2.13 to 4.0b2","author":"Michael Howitz","date":"October 25, 2017","format":false,"excerpt":"Beta-Testing Zope 4 together with PerFact Innovation","rel":"","context":"In "en"","block_context":{"text":"en","link":"https:\/\/blog.gocept.com\/category\/en\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1714,"url":"https:\/\/blog.gocept.com\/2016\/09\/29\/zope-resurrection-part-1-reanimation\/","url_meta":{"origin":2890,"position":1},"title":"Zope Resurrection Part 1 \u2013 Reanimation","author":"Michael Howitz","date":"September 29, 2016","format":false,"excerpt":"Now we\u00a0are helping\u00a0Zope in the Python 3 wonderland:\u00a0Almost 20 people started with the reanimation of Zope. We are working mostly on porting important dependencies of Zope to Python 3: RestrictedPython In the discussion we found out that the through the web (TTW) approach needs to be kept in Zope because\u2026","rel":"","context":"In "en"","block_context":{"text":"en","link":"https:\/\/blog.gocept.com\/category\/en\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.gocept.com\/wp-content\/uploads\/2016\/09\/img_2583-1.jpg?fit=1200%2C675&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.gocept.com\/wp-content\/uploads\/2016\/09\/img_2583-1.jpg?fit=1200%2C675&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/blog.gocept.com\/wp-content\/uploads\/2016\/09\/img_2583-1.jpg?fit=1200%2C675&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/blog.gocept.com\/wp-content\/uploads\/2016\/09\/img_2583-1.jpg?fit=1200%2C675&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/blog.gocept.com\/wp-content\/uploads\/2016\/09\/img_2583-1.jpg?fit=1200%2C675&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":1644,"url":"https:\/\/blog.gocept.com\/2016\/09\/26\/last-minute-information-for-remote-sprinters-for-the-zope-resurrection-sprint\/","url_meta":{"origin":2890,"position":2},"title":"Last minute information for remote Sprinters for the Zope Resurrection Sprint","author":"Steffen Allner","date":"September 26, 2016","format":false,"excerpt":"As the Zope Resurrection sprint is approaching, it seems useful to share some information on the schedule for the three days in Halle. As we have also some sprinters, who can not join on site, but might want to join remotely, a few key facts might come in handy. Etherpad\u2026","rel":"","context":"In "en"","block_context":{"text":"en","link":"https:\/\/blog.gocept.com\/category\/en\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2632,"url":"https:\/\/blog.gocept.com\/2017\/09\/22\/earl-zope-ii-is-dead-long-live-earl-zope\/","url_meta":{"origin":2890,"position":3},"title":"Earl Zope II is dead, long live Earl Zope","author":"Michael Howitz","date":"September 22, 2017","format":false,"excerpt":"Zope 4.0b1 released","rel":"","context":"In "en"","block_context":{"text":"en","link":"https:\/\/blog.gocept.com\/category\/en\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.gocept.com\/wp-content\/uploads\/2017\/09\/pexels-photo-68806-e1506067407549.jpg?fit=1200%2C832&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.gocept.com\/wp-content\/uploads\/2017\/09\/pexels-photo-68806-e1506067407549.jpg?fit=1200%2C832&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/blog.gocept.com\/wp-content\/uploads\/2017\/09\/pexels-photo-68806-e1506067407549.jpg?fit=1200%2C832&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/blog.gocept.com\/wp-content\/uploads\/2017\/09\/pexels-photo-68806-e1506067407549.jpg?fit=1200%2C832&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/blog.gocept.com\/wp-content\/uploads\/2017\/09\/pexels-photo-68806-e1506067407549.jpg?fit=1200%2C832&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":39,"url":"https:\/\/blog.gocept.com\/2011\/01\/24\/testing-pyramid-applications-with-zope-testbrowser\/","url_meta":{"origin":2890,"position":4},"title":"Testing pyramid applications with zope.testbrowser","author":"","date":"January 24, 2011","format":false,"excerpt":"The Pyramid documentation recommends using WebTest for functional tests, but coming from the Zope world, zope.testbrowser is the more familiar tool for this job (and it seems a little more high-level than WebTest at first glance). With the 3.11 release,\u00a0 zope.testbrowser gained out-of-the-box support for talking to WSGI applications (courtesy\u2026","rel":"","context":"In "en"","block_context":{"text":"en","link":"https:\/\/blog.gocept.com\/category\/en\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":3422,"url":"https:\/\/blog.gocept.com\/2021\/03\/08\/earl-zope-invites-to-sprint\/","url_meta":{"origin":2890,"position":5},"title":"Earl Zope invites to sprint","author":"Michael Howitz","date":"March 8, 2021","format":false,"excerpt":"Two Zope sprints at 23rd of April and 2nd of July 2021.","rel":"","context":"In "en"","block_context":{"text":"en","link":"https:\/\/blog.gocept.com\/category\/en\/"},"img":{"alt_text":"Regatta below a bridge","src":"https:\/\/i0.wp.com\/blog.gocept.com\/wp-content\/uploads\/2021\/03\/regatta-4565976_1280.jpg?fit=1200%2C800&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.gocept.com\/wp-content\/uploads\/2021\/03\/regatta-4565976_1280.jpg?fit=1200%2C800&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/blog.gocept.com\/wp-content\/uploads\/2021\/03\/regatta-4565976_1280.jpg?fit=1200%2C800&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/blog.gocept.com\/wp-content\/uploads\/2021\/03\/regatta-4565976_1280.jpg?fit=1200%2C800&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/blog.gocept.com\/wp-content\/uploads\/2021\/03\/regatta-4565976_1280.jpg?fit=1200%2C800&ssl=1&resize=1050%2C600 3x"},"classes":[]}],"_links":{"self":[{"href":"https:\/\/blog.gocept.com\/wp-json\/wp\/v2\/posts\/2890"}],"collection":[{"href":"https:\/\/blog.gocept.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.gocept.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.gocept.com\/wp-json\/wp\/v2\/users\/15344399"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.gocept.com\/wp-json\/wp\/v2\/comments?post=2890"}],"version-history":[{"count":25,"href":"https:\/\/blog.gocept.com\/wp-json\/wp\/v2\/posts\/2890\/revisions"}],"predecessor-version":[{"id":3209,"href":"https:\/\/blog.gocept.com\/wp-json\/wp\/v2\/posts\/2890\/revisions\/3209"}],"wp:attachment":[{"href":"https:\/\/blog.gocept.com\/wp-json\/wp\/v2\/media?parent=2890"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.gocept.com\/wp-json\/wp\/v2\/categories?post=2890"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.gocept.com\/wp-json\/wp\/v2\/tags?post=2890"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}History<\/h3>\n
standard_error_message<\/code>\u00a0(an object in the ZODB) was rendered. This way the error page could be customised through the web.<\/p>\n
standard_error_message<\/code>\u00a0is no longer used. The exceptions have to be handled in a WSGI middleware. (This is a sub-optimal solution as the middleware is not run in the same execution context where the exception occurred.)<\/p>\n
standard_error_message<\/code> is even gone when installing Zope 4 from scratch.<\/p>\n
Base solution<\/h3>\n
paster<\/code>:<\/p>\n
$ bin\/pip install PasteScript\r\n$ bin\/paster create -t basic_package errorviews\r\n$ bin\/pip install -e errorviews<\/pre>\n
errorviews<\/code>\u00a0is the name of my example package.<\/p>\n
errorviews\/__init__.py<\/code>enter the following code:<\/p>\n
class SiteErrorView(object):\r\n \"\"\"View rendered on SiteError.\"\"\"\r\n\r\n def __call__(self):\r\n return \"SiteError!\"<\/pre>\n
SiteError!<\/code>\u00a0instead of the standard error message. It has to be registered via ZCML. Write a file named
configure.zcml<\/code>\u00a0right besides
__init__.py<\/code>:<\/p>\n
<configure\r\n xmlns=\"http:\/\/namespaces.zope.org\/zope\"\r\n xmlns:browser=\"http:\/\/namespaces.zope.org\/browser\">\r\n\r\n <browser:page\r\n for=\"Exception\"\r\n name=\"index.html\"\r\n class=\".SiteErrorView\"\r\n permission=\"zope.Public\"\r\n \/>\r\n\r\n<\/configure><\/pre>\n
Exception<\/code>\u00a0and all classes inheriting from it. (This might be a bit too general for use in actual code, I know.) Zope 4 expects that the name is\u00a0
index.html<\/code>.
class<\/code>\u00a0 is a relative dotted path to the view class.<\/p>\n
errorviews<\/code>\u00a0package like me you have to register it in
etc\/site.zcml<\/code>\u00a0. Put the following line near the end before
<\/configure><\/code>:<\/p>\n
\u00a0<include package=\"errorviews\" \/><\/pre>\n
SiteError!<\/code><\/p>\n
Using a PageTemplate<\/h3>\n
error.pt<\/code>\u00a0right beside\u00a0
__init__.py<\/code>:<\/p>\n
<html>\r\n <body>\r\n <h1>SiteError occurred<\/h1>\r\n <\/body>\r\n<\/html>\r\n<\/pre>\n
configure.zcml<\/code>\u00a0replace
class=\".SiteErrorView\"<\/code> by
template=\"error.pt\"<\/code>. (The view class is not used in this example.) After re-starting Zope each exception renders the HTML page.<\/p>\n
Back to
standard_error_message<\/code><\/h3>\n
Data.fs<\/code>\u00a0and want to re-use
standard_error_message<\/code>\u00a0you might try the following hack: Change\u00a0
configure.zcml<\/code>\u00a0(back) to the XML code shown in the section “Base solution”. \u00a0Change
__init__.py<\/code>\u00a0to the following content:<\/p>\n
class SiteErrorView(object):\r\n \"\"\"View rendered on SiteError.\"\"\"\r\n\r\n def __call__(self):\r\n root = self.request['PARENTS'][-1]\r\n return root.standard_error_message(\r\n error_type=self.context.__class__.__name__,\r\n error_value=str(self.context))<\/pre>\n
standard_error_message<\/code>\u00a0 is a
DTMLMethod<\/code>\u00a0(as provided by Zope 2.13). The arguments
error_type<\/code>\u00a0 and
error_value<\/code>\u00a0 allow using\u00a0
&dtml-error_type;<\/code> and
&dtml-error_value;<\/code>\u00a0in the
DTMLMethod<\/code>\u00a0as before.<\/p>\n
Conclusion<\/h3>\n
standard_error_message<\/code>\u00a0if needed. But I think this should only be used for old applications or as an interim solution.<\/p>\n","protected":false},"excerpt":{"rendered":"