changeset 350769ccdfa5 in trytond:default
details: https://hg.tryton.org/trytond?cmd=changeset;node=350769ccdfa5
description:
        Pass app and request to wsgi error handlers

        issue8548
        review271931002
diffstat:

 CHANGELOG                  |    1 +
 trytond/tests/test_wsgi.py |  118 +++++++++++++++++++++++++++++++++++++++++++++
 trytond/wsgi.py            |    6 +-
 3 files changed, 124 insertions(+), 1 deletions(-)

diffs (153 lines):

diff -r 38d1b3a57920 -r 350769ccdfa5 CHANGELOG
--- a/CHANGELOG Mon Sep 02 18:21:41 2019 +0200
+++ b/CHANGELOG Mon Sep 02 18:25:12 2019 +0200
@@ -1,3 +1,4 @@
+* Pass app and request to wsgi error handlers
 * Add lazy_gettext
 * Add format_timedelta to Report
 * Add partial TO_CHAR support for date and datetime on SQLite
diff -r 38d1b3a57920 -r 350769ccdfa5 trytond/tests/test_wsgi.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/trytond/tests/test_wsgi.py        Mon Sep 02 18:25:12 2019 +0200
@@ -0,0 +1,118 @@
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+
+import unittest
+from unittest.mock import Mock, sentinel
+
+from werkzeug.wrappers import Response
+from werkzeug.test import Client
+from trytond.wsgi import TrytondWSGI
+from trytond.exceptions import TrytonException
+
+
+class WSGIAppTestCase(unittest.TestCase):
+    'Test WSGI Application'
+
+    class TestException(TrytonException):
+        pass
+
+    def test_one_error_handler_called(self):
+        """Test an error handler is called
+        with the app, the request and the exception."""
+        app = TrytondWSGI()
+        spy = Mock()
+
+        @app.error_handler
+        def _handler(*args, **kwargs):
+            spy(*args, **kwargs)
+
+        exception = self.TestException('foo')
+
+        @app.route('/willfail')
+        def _route(request):
+            sentinel.request = request
+            raise exception
+
+        client = Client(app)
+        (response, status, headers) = client.get('/willfail')
+
+        spy.assert_called_once_with(app, sentinel.request, exception)
+
+    def test_many_error_handlers_called(self):
+        "Test many error handlers are called"
+        app = TrytondWSGI()
+        spy1 = Mock()
+        spy2 = Mock()
+
+        @app.error_handler
+        def _handler1(*args, **kwargs):
+            spy1(*args, **kwargs)
+
+        @app.error_handler
+        def _handler2(*args, **kwargs):
+            spy2(*args, **kwargs)
+
+        exception = self.TestException('foo')
+
+        @app.route('/willfail')
+        def _route(request):
+            sentinel.request = request
+            raise exception
+
+        client = Client(app)
+        (response, status, headers) = client.get('/willfail')
+
+        spy1.assert_called_once_with(app, sentinel.request, exception)
+        spy2.assert_called_once_with(app, sentinel.request, exception)
+
+    def test_class_error_handler_called(self):
+        "Test class error handlers can be used"
+        app = TrytondWSGI()
+        spy = Mock()
+
+        class ErrorHandler():
+            def __call__(self, *args, **kwargs):
+                spy(*args, **kwargs)
+
+        app.error_handler(ErrorHandler())
+
+        exception = self.TestException('foo')
+
+        @app.route('/willfail')
+        def _route(request):
+            sentinel.request = request
+            raise exception
+
+        client = Client(app)
+        (response, status, headers) = client.get('/willfail')
+
+        spy.assert_called_once_with(app, sentinel.request, exception)
+
+    def test_error_handlers_last_response(self):
+        "Test last handler response is used"
+        app = TrytondWSGI()
+
+        @app.error_handler
+        def _handler1(*args, **kwargs):
+            return Response(b'bar')
+
+        @app.error_handler
+        def _handler2(*args, **kwargs):
+            return Response(b'baz', status=418)
+
+        @app.route('/willfail')
+        def _route(request):
+            raise self.TestException('foo')
+
+        client = Client(app)
+        (response, status, headers) = client.get('/willfail')
+
+        self.assertEqual(next(response), b'baz')
+        self.assertEqual(status, "418 I'M A TEAPOT")
+
+
+def suite():
+    suite_ = unittest.TestSuite()
+    suite_.addTests(
+        unittest.TestLoader().loadTestsFromTestCase(WSGIAppTestCase))
+    return suite_
diff -r 38d1b3a57920 -r 350769ccdfa5 trytond/wsgi.py
--- a/trytond/wsgi.py   Mon Sep 02 18:21:41 2019 +0200
+++ b/trytond/wsgi.py   Mon Sep 02 18:25:12 2019 +0200
@@ -65,6 +65,10 @@
             return func
         return decorator
 
+    def error_handler(self, handler):
+        self.error_handlers.append(handler)
+        return handler
+
     @wrapt.decorator
     def auth_required(self, wrapped, instance, args, kwargs):
         request = args[0]
@@ -111,7 +115,7 @@
             e.__format_traceback__ = tb_s
             response = e
             for error_handler in self.error_handlers:
-                rv = error_handler(e)
+                rv = error_handler(self, request, e)
                 if isinstance(rv, Response):
                     response = rv
             return response

Reply via email to