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

Last change on this file since 1403 was 1392, checked in by wouter, 6 days ago

v1.1.4 now has ExceptionContainer to wrap python excceptions (from stacktarce)

File size: 4.2 KB
RevLine 
[1392]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
72 def getClassName(self) -> str:
73 return self.__classname
74
75 def getMessage(self)->str :
76 return self.__message
77
78 def getStackTrace(self) -> List[str]:
79 return self.__stacktrace
80
81 def getCause(self) ->Optional[ExceptionContainer]:
82 return self.__cause
83
84 def toJson(self):
85 '''
86 bit hacky, avoid use of pyson here to keep the libraries independent
87 '''
88 return {'classname':self.__classname, 'message':self.__message,
89 'stacktrace':self.__stacktrace, 'cause':self.__cause}
90
91 def __repr__(self):
92 mesg:str = self.__classname + ":" + self.__message + "\n"\
93 + "\n".join(self.__stacktrace)
94 if self.__cause != None:
95 mesg = mesg + "\n caused by:\n" + str(self.__cause)
96 return mesg;
97
98 def __hash__(self):
99 return hash((self.__cause, self.__classname, self.__message, self.__stacktrace))
100
101 def __eq__(self, obj):
102 if self == obj:
103 return True
104 if obj == None:
105 return False
106 if type(self) != type(obj):
107 return False
108 return self.__cause==obj.cause \
109 and self.__classname == obj.classname \
110 and self.__message == obj.message \
111 and self.__stacktrace == obj.stacktrace
Note: See TracBrowser for help on using the repository browser.