Skip to content

Commit 21b27cf

Browse files
epiqueraskibergus
authored andcommitted
Make stacktraces more readable by dropping excessive helper methods from them.
PiperOrigin-RevId: 809748640
1 parent 2ee9096 commit 21b27cf

File tree

2 files changed

+8
-62
lines changed

2 files changed

+8
-62
lines changed

genai_processors/context.py

Lines changed: 2 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import asyncio
1818
from collections.abc import Coroutine, Iterable
1919
import contextvars
20-
import types
2120
from typing import Any, TypeVar
2221

2322
from absl import logging
@@ -39,52 +38,11 @@
3938

4039

4140
def raise_flattened_exception_group(exception: Exception):
42-
"""Flattens the exception group and filters the traceback."""
43-
exceptions_in_group = 0
4441
e = exception
4542
while isinstance(e, ExceptionGroup):
46-
exceptions_in_group += len(e.exceptions)
4743
e = e.exceptions[0]
48-
49-
# Every processor invocation is wrapperd in a couple of helpers, significantly
50-
# inflating the callstack. Here we manipulate it and leave only the most
51-
# nested instances of these helper, making stacktraces more readable.
52-
processors_internal_functions = [
53-
'_normalize_part_stream',
54-
'_enqueue_content',
55-
'__call__',
56-
]
57-
observed_functions = set()
58-
59-
if e.__traceback__ is not None:
60-
frames = []
61-
tb = e.__traceback__
62-
while tb is not None:
63-
frames.append(tb)
64-
tb = tb.tb_next
65-
66-
tb = None
67-
for frame in reversed(frames):
68-
if frame.tb_frame.f_code.co_filename.endswith(
69-
'genai_processors/processor.py'
70-
):
71-
function_name = frame.tb_frame.f_code.co_name
72-
if function_name in processors_internal_functions:
73-
if function_name in observed_functions:
74-
continue
75-
observed_functions.add(function_name)
76-
77-
tb = types.TracebackType(
78-
tb_next=tb,
79-
tb_frame=frame.tb_frame,
80-
tb_lasti=frame.tb_lasti,
81-
tb_lineno=frame.tb_lineno,
82-
)
83-
84-
e.__traceback__ = tb
85-
86-
if e is exception or exceptions_in_group <= 1:
87-
raise e from None
44+
if e is exception:
45+
raise exception
8846
else:
8947
raise e from exception
9048

genai_processors/tests/processor_test.py

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,18 @@ async def processor_0(
149149
# Using assertRaises removes the traceback which we want to check
150150
# includes the TaskGroup error.
151151
exception = None
152+
tb = None
152153
try:
153154
processor.apply_sync(
154155
processor_0, content_api.ProcessorContent(['foo', 'bar'])
155156
)
156157
except ValueError as e:
157158
exception = str(e)
159+
tb = traceback.format_exc()
158160

159161
# Assert that the error message isn't a generic ExceptionGroup message
160162
self.assertNotIn('unhandled errors in a TaskGroup', exception)
163+
self.assertIn('unhandled errors in a TaskGroup', tb)
161164
self.assertEqual(exception, err_msg)
162165

163166
def test_chained_part_processor_raises_specific_error_message(self):
@@ -176,15 +179,18 @@ async def processor_0(
176179
# Using assertRaises removes the traceback which we want to check
177180
# includes the TaskGroup error.
178181
exception = None
182+
tb = None
179183
try:
180184
processor.apply_sync(
181185
combined_processor, [content_api.ProcessorPart('bar')]
182186
)
183187
except ValueError as e:
184188
exception = str(e)
189+
tb = traceback.format_exc()
185190

186191
# Assert that the error message isn't a generic ExceptionGroup message
187192
self.assertNotIn('unhandled errors in a TaskGroup', exception)
193+
self.assertIn('unhandled errors in a TaskGroup', tb)
188194
self.assertEqual(exception, err_msg)
189195

190196
def test_normalization_function(self):
@@ -999,24 +1005,6 @@ async def proc_c(
9991005
content = processor.apply_sync(chain_abc, inputs)
10001006
self.assertEqual(content, inputs)
10011007

1002-
def test_backtrace_optimization(self):
1003-
@processor.part_processor_function
1004-
async def fail(
1005-
part: content_api.ProcessorPart,
1006-
) -> AsyncIterable[content_api.ProcessorPart]:
1007-
raise ValueError('foo is not allowed')
1008-
yield part # pylint: disable=unreachable
1009-
1010-
p = processor.passthrough()
1011-
1012-
inputs = [content_api.ProcessorPart('0')]
1013-
try:
1014-
processor.apply_sync(p + p + fail, inputs)
1015-
except ValueError:
1016-
tb = traceback.format_exc()
1017-
self.assertIn('foo is not allowed', tb) # pylint: disable=g-assert-in-except
1018-
self.assertEqual(tb.count('_normalize_part_stream\n'), 1) # pylint: disable=g-assert-in-except
1019-
10201008

10211009
class ParallelProcessorsTest(TestWithProcessors, parameterized.TestCase):
10221010

0 commit comments

Comments
 (0)