bt2: reverse order of printed causes in _Error.__str__
[babeltrace.git] / src / bindings / python / bt2 / bt2 / error.py
1 from bt2 import native_bt
2 from collections import abc
3
4
5 class ComponentClassType:
6 SOURCE = native_bt.COMPONENT_CLASS_TYPE_SOURCE
7 FILTER = native_bt.COMPONENT_CLASS_TYPE_FILTER
8 SINK = native_bt.COMPONENT_CLASS_TYPE_SINK
9
10
11 _COMPONENT_CLASS_TYPE_TO_STR = {
12 native_bt.COMPONENT_CLASS_TYPE_SOURCE: 'source',
13 native_bt.COMPONENT_CLASS_TYPE_FILTER: 'filter',
14 native_bt.COMPONENT_CLASS_TYPE_SINK: 'sink',
15 }
16
17
18 def _create_error_cause_from_ptr(ptr):
19 actor_type = native_bt.error_cause_get_actor_type(ptr)
20 return _ACTOR_TYPE_TO_CLS[actor_type](ptr)
21
22
23 class _ErrorCause:
24 def __init__(self, ptr):
25 self._message = native_bt.error_cause_get_message(ptr)
26 self._module_name = native_bt.error_cause_get_module_name(ptr)
27 self._file_name = native_bt.error_cause_get_file_name(ptr)
28 self._line_number = native_bt.error_cause_get_line_number(ptr)
29
30 def __str__(self):
31 s = '[{}] ({}:{})\n'.format(self.module_name, self.file_name, self.line_number)
32 s += self.message
33 return s
34
35 @property
36 def message(self):
37 return self._message
38
39 @property
40 def module_name(self):
41 return self._module_name
42
43 @property
44 def file_name(self):
45 return self._file_name
46
47 @property
48 def line_number(self):
49 return self._line_number
50
51
52 class _ComponentErrorCause(_ErrorCause):
53 def __init__(self, ptr):
54 super().__init__(ptr)
55 self._component_name = native_bt.error_cause_component_actor_get_component_name(
56 ptr
57 )
58 self._component_class_type = native_bt.error_cause_component_actor_get_component_class_type(
59 ptr
60 )
61 self._component_class_name = native_bt.error_cause_component_actor_get_component_class_name(
62 ptr
63 )
64 self._plugin_name = native_bt.error_cause_component_actor_get_plugin_name(ptr)
65
66 @property
67 def component_name(self):
68 return self._component_name
69
70 @property
71 def component_class_type(self):
72 return self._component_class_type
73
74 @property
75 def component_class_name(self):
76 return self._component_class_name
77
78 @property
79 def plugin_name(self):
80 return self._plugin_name
81
82
83 class _ComponentClassErrorCause(_ErrorCause):
84 def __init__(self, ptr):
85 super().__init__(ptr)
86 self._component_class_type = native_bt.error_cause_component_class_actor_get_component_class_type(
87 ptr
88 )
89 self._component_class_name = native_bt.error_cause_component_class_actor_get_component_class_name(
90 ptr
91 )
92 self._plugin_name = native_bt.error_cause_component_class_actor_get_plugin_name(
93 ptr
94 )
95
96 @property
97 def component_class_type(self):
98 return self._component_class_type
99
100 @property
101 def component_class_name(self):
102 return self._component_class_name
103
104 @property
105 def plugin_name(self):
106 return self._plugin_name
107
108
109 class _MessageIteratorErrorCause(_ErrorCause):
110 def __init__(self, ptr):
111 super().__init__(ptr)
112 self._component_name = native_bt.error_cause_message_iterator_actor_get_component_name(
113 ptr
114 )
115 self._component_output_port_name = native_bt.error_cause_message_iterator_actor_get_component_output_port_name(
116 ptr
117 )
118 self._component_class_type = native_bt.error_cause_message_iterator_actor_get_component_class_type(
119 ptr
120 )
121 self._component_class_name = native_bt.error_cause_message_iterator_actor_get_component_class_name(
122 ptr
123 )
124 self._plugin_name = native_bt.error_cause_message_iterator_actor_get_plugin_name(
125 ptr
126 )
127
128 @property
129 def component_name(self):
130 return self._component_name
131
132 @property
133 def component_output_port_name(self):
134 return self._component_output_port_name
135
136 @property
137 def component_class_type(self):
138 return self._component_class_type
139
140 @property
141 def component_class_name(self):
142 return self._component_class_name
143
144 @property
145 def plugin_name(self):
146 return self._plugin_name
147
148
149 _ACTOR_TYPE_TO_CLS = {
150 native_bt.ERROR_CAUSE_ACTOR_TYPE_UNKNOWN: _ErrorCause,
151 native_bt.ERROR_CAUSE_ACTOR_TYPE_COMPONENT: _ComponentErrorCause,
152 native_bt.ERROR_CAUSE_ACTOR_TYPE_COMPONENT_CLASS: _ComponentClassErrorCause,
153 native_bt.ERROR_CAUSE_ACTOR_TYPE_MESSAGE_ITERATOR: _MessageIteratorErrorCause,
154 }
155
156
157 class _Error(Exception, abc.Sequence):
158 """
159 Babeltrace API call error.
160
161 This exception is raised when a call to the Babeltrace API returns with
162 the ERROR or MEMORY_ERROR status codes.
163 """
164
165 def __init__(self, msg):
166 super().__init__(msg)
167 # Steal the current thread's error.
168 self._ptr = native_bt.current_thread_take_error()
169 assert self._ptr is not None
170
171 self._msg = msg
172
173 # Read everything we might need from the error pointer, so we don't
174 # depend on it. It's possible for the user to keep an Error object
175 # and to want to read its causes after the error pointer has been
176 # restored as the current thread's error (and is therefore
177 # inaccessible).
178 cause_count = native_bt.error_get_cause_count(self._ptr)
179
180 # We expect the library to append at least one cause (otherwise there
181 # wouldn't be an bt_error object anyway). Also, while formatting the
182 # exception, the Python `traceback` module does:
183 #
184 # if (exc_value and ...):
185 #
186 # If the cause list was empty, this would evaluate to False (which we
187 # wouldn't want), because of the __bool__ implementation of
188 # abc.Sequence. If there's at least one cause, we are sure that
189 # __bool__ will always return True and avoid any problem here.
190 assert cause_count > 0
191
192 self._causes = []
193
194 for i in range(cause_count):
195 cause_ptr = native_bt.error_borrow_cause_by_index(self._ptr, i)
196 assert cause_ptr is not None
197 cause = _create_error_cause_from_ptr(cause_ptr)
198 self._causes.append(cause)
199
200 def __del__(self):
201 # If this exception escapes all the way out of the Python code, the
202 # native code will steal `_ptr` to restore it as the current thread's
203 # error. If the exception is caught and discarded by the Python code,
204 # the exception object still owns the error, so we must release it.
205 if self._ptr is not None:
206 native_bt.error_release(self._ptr)
207
208 def __getitem__(self, index):
209 return self._causes[index]
210
211 def __len__(self):
212 return len(self._causes)
213
214 def __str__(self):
215 s = self._msg + '\n'
216 for c in reversed(self):
217 s += str(c) + '\n'
218 return s
This page took 0.033244 seconds and 4 git commands to generate.