source: utilitiespy/tudelft/utilities/exception/ExceptionContainer.py@ 1421

Last change on this file since 1421 was 1409, checked in by wouter, 4 days ago

extend ExceptionContainer with fromException

File size: 4.7 KB
Line 
1from __future__ import annotations
2from typing import Optional, List
3
4class ExceptionContainer:
5 '''
6 An exception container contains the contents of an exception.
7 It's a standard frmat shared with Java so that we can exchange exceptions.
8 @param classname the class name of the exception, eg eg
9 "java.lang.NullPointerException", "AttributeError"
10 @param message short human-readable message explaining what happened.
11 null is used as "".
12 @param stacktrace a list of strings, each a stack point. May contain
13 filename, class name, line number, column number. Kept
14 general for now as currently this is intended for human
15 use only
16 @param cause another {@link ExceptionContainer} holding the
17 exception that caused this, or None if there was no
18 other cause.
19 '''
20 def __init__(self, classname:str, message:Optional[str],
21 stacktrace:List[str],cause: Optional[ExceptionContainer] ):
22 if classname == None or stacktrace == None:
23 raise AttributeError("classname and stacktrace must be not None")
24 self.__classname = classname
25 self.__message:str = "" if message == None else message
26 self.__stacktrace = stacktrace
27 self.__cause = cause
28
29
30 @staticmethod
31 def create( trace:str) -> ExceptionContainer:
32 '''
33 This creates a ExceptionContainer from a trace message.
34 The trace message is found in the errors and failures fields
35 of a TestResult object. The error field contains a list of tuples
36 and the 2nd tuple is the trace message.
37 It looks like a general error message, eg
38 Traceback (...):
39 File "blabla.py", line 22 in class1:
40 method(...)
41 File "blablabla.py" line 11 in class2:
42 raise blabla(....)
43 SomeErorr: errormessageblabla
44
45 The above exception was the direct cause .....
46
47 Traceback (....):
48 File ....
49
50
51 This trace message needs to be decyphered into a ExceptionContainer format
52 '''
53 return ExceptionContainer.create1(trace.split("\nThe above exception was the direct cause of the following exception:\n\n"),None)
54
55 @staticmethod
56 def create1(traces:List[str], cause:Optional[ExceptionContainer] ):
57 if len(traces)==0:
58 return cause
59 # there are more causes. process the first
60 trace = traces[0].split("\n")
61 err = trace[-1].split(":",1)
62 clazz = err[0]
63 message=err[1]
64 stacklist=trace[:-1]
65
66 # pre-pend this new cause before the existing cause
67 cause = ExceptionContainer(clazz, message, stacklist, cause)
68 # and continue with rest of the traces
69 return ExceptionContainer.create1(traces[1:],cause)
70
71 @staticmethod
72 def fromException(t:Exception) -> Optional[ExceptionContainer]:
73 '''
74 creates container holding given exxception.
75 Note that python exceptions do not contain a stacktrace.
76 NOTE you may want to use create(stacktrace).
77 '''
78 msg:str = t.args[0] if t.args else ""
79 name:str = type(t).__name__;
80 cause:Optional[ExceptionContainer] = None if not t.__cause__ else \
81 ExceptionContainer.fromException(t.__cause__)
82 return ExceptionContainer(name, msg, [],cause);
83
84 def getClassName(self) -> str:
85 return self.__classname
86
87 def getMessage(self)->str :
88 return self.__message
89
90 def getStackTrace(self) -> List[str]:
91 return self.__stacktrace
92
93 def getCause(self) ->Optional[ExceptionContainer]:
94 return self.__cause
95
96 def toJson(self):
97 '''
98 bit hacky, avoid use of pyson here to keep the libraries independent
99 '''
100 return {'classname':self.__classname, 'message':self.__message,
101 'stacktrace':self.__stacktrace, 'cause':self.__cause}
102
103 def __repr__(self):
104 mesg:str = self.__classname + ":" + self.__message + "\n"\
105 + "\n".join(self.__stacktrace)
106 if self.__cause != None:
107 mesg = mesg + "\n caused by:\n" + str(self.__cause)
108 return mesg;
109
110 def __hash__(self):
111 return hash((self.__cause, self.__classname, self.__message, self.__stacktrace))
112
113 def __eq__(self, obj):
114 if self == obj:
115 return True
116 if obj == None:
117 return False
118 if type(self) != type(obj):
119 return False
120 return self.__cause==obj.cause \
121 and self.__classname == obj.classname \
122 and self.__message == obj.message \
123 and self.__stacktrace == obj.stacktrace
Note: See TracBrowser for help on using the repository browser.