Browse Source

add debug mode in contexts to display exceptions info only in debug mode

Bastien Sevajol 6 years ago
parent
commit
fd3d43adb4

+ 9 - 0
hapic/context.py View File

135
         """
135
         """
136
         raise NotImplementedError()
136
         raise NotImplementedError()
137
 
137
 
138
+    def is_debug(self) -> bool:
139
+        """
140
+        Method called to know if Hapic has been called in debug mode.
141
+        Debug mode provide some informations like debug trace and error
142
+        message in body when internal error happen.
143
+        :return: True if in debug mode
144
+        """
145
+        raise NotImplementedError()
146
+
138
 
147
 
139
 class HandledException(object):
148
 class HandledException(object):
140
     """
149
     """

+ 24 - 4
hapic/error.py View File

1
 # -*- coding: utf-8 -*-
1
 # -*- coding: utf-8 -*-
2
+import traceback
3
+
2
 import marshmallow
4
 import marshmallow
3
 
5
 
4
 from hapic.processor import ProcessValidationError
6
 from hapic.processor import ProcessValidationError
9
     ErrorBuilder is a class who represent a Schema (marshmallow.Schema) and
11
     ErrorBuilder is a class who represent a Schema (marshmallow.Schema) and
10
     can generate a response content from exception (build_from_exception)
12
     can generate a response content from exception (build_from_exception)
11
     """
13
     """
12
-    def build_from_exception(self, exception: Exception) -> dict:
14
+    def build_from_exception(
15
+        self,
16
+        exception: Exception,
17
+        include_traceback: bool = False,
18
+    ) -> dict:
13
         """
19
         """
14
         Build the error response content from given exception
20
         Build the error response content from given exception
15
         :param exception: Original exception who invoke this method
21
         :param exception: Original exception who invoke this method
34
     details = marshmallow.fields.Dict(required=False, missing={})
40
     details = marshmallow.fields.Dict(required=False, missing={})
35
     code = marshmallow.fields.Raw(missing=None)
41
     code = marshmallow.fields.Raw(missing=None)
36
 
42
 
37
-    def build_from_exception(self, exception: Exception) -> dict:
43
+    def build_from_exception(
44
+        self,
45
+        exception: Exception,
46
+        include_traceback: bool = False,
47
+    ) -> dict:
38
         """
48
         """
39
         See hapic.error.ErrorBuilderInterface#build_from_exception docstring
49
         See hapic.error.ErrorBuilderInterface#build_from_exception docstring
40
         """
50
         """
41
         # TODO: "error_detail" attribute name should be configurable
51
         # TODO: "error_detail" attribute name should be configurable
52
+        message = str(exception)
53
+        if not message:
54
+            message = type(exception).__name__
55
+
56
+        details = {
57
+            'error_detail': getattr(exception, 'error_detail', {}),
58
+        }
59
+        if include_traceback:
60
+            details['traceback'] = traceback.format_exc()
61
+
42
         return {
62
         return {
43
-            'message': str(exception),
44
-            'details': getattr(exception, 'error_detail', {}),
63
+            'message': message,
64
+            'details': details,
45
             'code': None,
65
             'code': None,
46
         }
66
         }
47
 
67
 

+ 5 - 0
hapic/ext/bottle/context.py View File

33
         self,
33
         self,
34
         app: bottle.Bottle,
34
         app: bottle.Bottle,
35
         default_error_builder: ErrorBuilderInterface=None,
35
         default_error_builder: ErrorBuilderInterface=None,
36
+        debug: bool = False,
36
     ):
37
     ):
37
         self._handled_exceptions = []  # type: typing.List[HandledException]  # nopep8
38
         self._handled_exceptions = []  # type: typing.List[HandledException]  # nopep8
38
         self._exceptions_handler_installed = False
39
         self._exceptions_handler_installed = False
39
         self.app = app
40
         self.app = app
40
         self.default_error_builder = \
41
         self.default_error_builder = \
41
             default_error_builder or DefaultErrorBuilder()  # FDV
42
             default_error_builder or DefaultErrorBuilder()  # FDV
43
+        self.debug = debug
42
 
44
 
43
     def get_request_parameters(self, *args, **kwargs) -> RequestParameters:
45
     def get_request_parameters(self, *args, **kwargs) -> RequestParameters:
44
         path_parameters = dict(bottle.request.url_args)
46
         path_parameters = dict(bottle.request.url_args)
164
         See hapic.context.BaseContext#_get_handled_exception_class_and_http_codes  # nopep8
166
         See hapic.context.BaseContext#_get_handled_exception_class_and_http_codes  # nopep8
165
         """
167
         """
166
         return self._handled_exceptions
168
         return self._handled_exceptions
169
+
170
+    def is_debug(self) -> bool:
171
+        return self.debug

+ 5 - 0
hapic/ext/flask/context.py View File

32
         self,
32
         self,
33
         app: Flask,
33
         app: Flask,
34
         default_error_builder: ErrorBuilderInterface=None,
34
         default_error_builder: ErrorBuilderInterface=None,
35
+        debug: bool = False,
35
     ):
36
     ):
36
         self._handled_exceptions = []  # type: typing.List[HandledException]  # nopep8
37
         self._handled_exceptions = []  # type: typing.List[HandledException]  # nopep8
37
         self.app = app
38
         self.app = app
38
         self.default_error_builder = \
39
         self.default_error_builder = \
39
             default_error_builder or DefaultErrorBuilder()  # FDV
40
             default_error_builder or DefaultErrorBuilder()  # FDV
41
+        self.debug = debug
40
 
42
 
41
     def get_request_parameters(self, *args, **kwargs) -> RequestParameters:
43
     def get_request_parameters(self, *args, **kwargs) -> RequestParameters:
42
         from flask import request
44
         from flask import request
165
         http_code: int,
167
         http_code: int,
166
     ) -> None:
168
     ) -> None:
167
         raise NotImplementedError('TODO')
169
         raise NotImplementedError('TODO')
170
+
171
+    def is_debug(self) -> bool:
172
+        return self.debug

+ 5 - 0
hapic/ext/pyramid/context.py View File

31
         self,
31
         self,
32
         configurator: 'Configurator',
32
         configurator: 'Configurator',
33
         default_error_builder: ErrorBuilderInterface = None,
33
         default_error_builder: ErrorBuilderInterface = None,
34
+        debug: bool = False,
34
     ):
35
     ):
35
         self._handled_exceptions = []  # type: typing.List[HandledException]  # nopep8
36
         self._handled_exceptions = []  # type: typing.List[HandledException]  # nopep8
36
         self.configurator = configurator
37
         self.configurator = configurator
37
         self.default_error_builder = \
38
         self.default_error_builder = \
38
             default_error_builder or DefaultErrorBuilder()  # FDV
39
             default_error_builder or DefaultErrorBuilder()  # FDV
40
+        self.debug = debug
39
 
41
 
40
     def get_request_parameters(self, *args, **kwargs) -> RequestParameters:
42
     def get_request_parameters(self, *args, **kwargs) -> RequestParameters:
41
         req = args[-1]  # TODO : Check
43
         req = args[-1]  # TODO : Check
189
         http_code: int,
191
         http_code: int,
190
     ) -> None:
192
     ) -> None:
191
         raise NotImplementedError('TODO')
193
         raise NotImplementedError('TODO')
194
+
195
+    def is_debug(self) -> bool:
196
+        return self.debug

+ 5 - 1
tests/unit/test_decorator.py View File

314
             pass
314
             pass
315
 
315
 
316
         class MyErrorBuilder(DefaultErrorBuilder):
316
         class MyErrorBuilder(DefaultErrorBuilder):
317
-            def build_from_exception(self, exception: Exception) -> dict:
317
+            def build_from_exception(
318
+                self,
319
+                exception: Exception,
320
+                include_traceback: bool = False,
321
+            ) -> dict:
318
                 # this is not matching with DefaultErrorBuilder schema
322
                 # this is not matching with DefaultErrorBuilder schema
319
                 return {}
323
                 return {}
320
 
324