1
0

system.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import traceback
  2. import sys
  3. from typing import List, Tuple
  4. from textwrap import dedent
  5. import html
  6. class Error:
  7. """Format class for errors including the exception
  8. and traceback.
  9. Parameters
  10. ----------
  11. contet_type : str
  12. Content type for which the error is meant to be rendered
  13. on.
  14. exception : Exception
  15. Exception object. If not passed, current stack trace is used.
  16. """
  17. def __init__(self, content_type="text", exception:Exception=None):
  18. self.content_type = content_type
  19. self.exception = exception
  20. def __str__(self):
  21. if self.content_type == "text":
  22. return self.as_text()
  23. elif self.content_type == "html-inline":
  24. return self.as_html_inline()
  25. elif self.content_type == "html":
  26. return self.as_html()
  27. else:
  28. raise ValueError(f"Invalid content_type: {self.content_type}")
  29. def __bool__(self):
  30. "Return true if there is an error, false if not"
  31. exc_type, _, _ = self.exc_format()
  32. return exc_type is not None
  33. def as_text(self):
  34. "Format traceback as text"
  35. exc_type, exc_text, tb_list = self.exc_format()
  36. tb_text = '\n'.join(tb_list)
  37. return f"""Traceback (most recent call last):\n{tb_text}\n{exc_type}: {exc_text}"""
  38. def as_html_inline(self):
  39. "Format traceback as HTML"
  40. exc_type, exc_text, tb_list = self.exc_format()
  41. tb_str = '\n'.join(tb_list)
  42. if tb_str.endswith('\n'):
  43. tb_str = tb_str[:-1]
  44. exc_type, exc_text, tb_str = (html.escape(val) for val in (exc_type, exc_text, tb_str))
  45. return dedent(
  46. f"""
  47. <div>
  48. <h4>Traceback (most recent call last):</h4>
  49. <pre><code>{tb_str}</code></pre>
  50. <span style="color: red; font-weight: bold">{exc_text}</span>: <span>{exc_type}</span>
  51. </div>"""
  52. )
  53. def as_html(self):
  54. "Format traceback as HTML"
  55. exc_type, exc_text, tb_list = self.exc_format()
  56. tb_str = '\n'.join(tb_list)
  57. if tb_str.endswith('\n'):
  58. tb_str = tb_str[:-1]
  59. exc_type, exc_text, tb_str = (html.escape(val) for val in (exc_type, exc_text, tb_str))
  60. return dedent(
  61. f"""<div class="error">
  62. <h4 class="header">Traceback (most recent call last):</h4>
  63. <pre class="traceback"><code>{tb_str}</code></pre>
  64. <div class="exception">
  65. <span class="exception-type">{exc_type}</span>: <span class="exception-value">{exc_text}</span>
  66. </div>
  67. </div>"""
  68. )
  69. @property
  70. def exception_type(self) -> str:
  71. "str: Type of the exception (as string)"
  72. type_, _, _ = self.exc_format()
  73. return type_
  74. @property
  75. def exception_value(self) -> str:
  76. "str: Exception value (as string)"
  77. _, value, _ = self.exc_format()
  78. return value
  79. @property
  80. def traceback(self) -> List[str]:
  81. "list str: Traceback (as list of str)"
  82. _, _, tb = self.exc_format()
  83. return tb
  84. def exc_format(self) -> Tuple[str, str, List[str]]:
  85. if self.exception is None:
  86. exc_type, exc_value, tb = sys.exc_info()
  87. else:
  88. exc_value = self.exception
  89. exc_type = type(self.exception)
  90. tb = self.exception.__traceback__
  91. tb_list = traceback.format_tb(tb) if tb is not None else None
  92. exc_str = str(exc_value) if exc_value is not None else None
  93. exc_type_str = exc_type.__name__ if exc_type is not None else None
  94. return exc_type_str, exc_str, tb_list