From 8258c4bd94a2ed6e3c23cd6c21c331b75d1ae52b Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Thu, 19 Sep 2019 17:13:58 -0400 Subject: [PATCH] bt2: print error causes in bt2._Error.__str__ When working on Python tests where a bt2._Error escapes the test, I very often write the same thing to be able to visualize error causes: try: ... original code ... except bt2._Error as e: for c in e: print(c) raise By making bt2._Error.__str__ print the error causes, the causes will be printed automatically when a test fails this way. And from the point of view of a user of the bt2 package, I think it's quite useful to get the error causes right away, rather than having to write a snippet like the above. As a user of the library, if a bt2._Error escapes or if I print it, I'd be happy to get this very precise information. Also, not everyone might know from the start that it's possible to print detailed causes, and the otherwise default message is rather vague. It just says for example "Failed to add component to graph", without any other detail. So I think we would do users a service by printing the causes by default. Change-Id: I6f8c72b8e358d6e664c47a1a43c9a81c91a76239 Signed-off-by: Simon Marchi Reviewed-on: https://review.lttng.org/c/babeltrace/+/2070 Tested-by: jenkins Reviewed-by: Francis Deslauriers --- src/bindings/python/bt2/bt2/error.py | 8 ++++++++ tests/bindings/python/bt2/test_error.py | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/src/bindings/python/bt2/bt2/error.py b/src/bindings/python/bt2/bt2/error.py index dc1e65f5..77358683 100644 --- a/src/bindings/python/bt2/bt2/error.py +++ b/src/bindings/python/bt2/bt2/error.py @@ -168,6 +168,8 @@ class _Error(Exception, abc.Sequence): self._ptr = native_bt.current_thread_take_error() assert self._ptr is not None + self._msg = msg + # Read everything we might need from the error pointer, so we don't # depend on it. It's possible for the user to keep an Error object # and to want to read its causes after the error pointer has been @@ -208,3 +210,9 @@ class _Error(Exception, abc.Sequence): def __len__(self): return len(self._causes) + + def __str__(self): + s = self._msg + '\n' + for c in self: + s += str(c) + '\n' + return s diff --git a/tests/bindings/python/bt2/test_error.py b/tests/bindings/python/bt2/test_error.py index 821d30f5..0bdd6ce3 100644 --- a/tests/bindings/python/bt2/test_error.py +++ b/tests/bindings/python/bt2/test_error.py @@ -205,6 +205,15 @@ class ErrorTestCase(unittest.TestCase): self.assertEqual(cause.component_class_name, 'SourceWithFailingIter') self.assertIsNone(cause.plugin_name) + def test_str(self): + # Test __str__. We don't need to test the precise format used, but + # just that it doesn't miserably crash and that it contains some + # expected bits. + exc = self._run_failing_graph(SourceWithFailingIter, SinkWithExceptionChaining) + s = str(exc) + self.assertIn('[src (out): src.SourceWithFailingIter]', s) + self.assertIn('ValueError: oops', s) + if __name__ == '__main__': unittest.main() -- 2.34.1