Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

gh-98458: unittest: bugfix for infinite loop while handling chained exceptions that contain cycles#98459

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
gpshead merged 8 commits intopython:mainfromAlexTate:issue-98458
Dec 4, 2022
Merged
Show file tree
Hide file tree
Changes from1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
PrevPrevious commit
NextNext commit
Bugfix extended to properly handle exception cycles in _clean_traceba…
…cks. The "seen" set follows the approach used in the TracebackException class (thank you@iritkatriel for pointing it out)
  • Loading branch information
@AlexTate
AlexTate committedDec 1, 2022
commitc1004097eb5976c23645117b0c1653690726e735
33 changes: 33 additions & 0 deletionsLib/test/test_unittest/test_result.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -275,6 +275,39 @@ def get_exc_info():
self.assertEqual(len(dropped), 1)
self.assertIn("raise self.failureException(msg)", dropped[0])

def test_addFailure_filter_traceback_frames_chained_exception_cycle(self):
class Foo(unittest.TestCase):
def test_1(self):
pass

def get_exc_info():
try:
# Create two directionally opposed cycles
# __cause__ in one direction, __context__ in the other
# Only one is needed since they serve the same role in _clean_tracebacks()
# But this way we cover both possibilities if the code changes
A, B, C = Exception("A"), Exception("B"), Exception("C")
edges = [(C, B), (B, A), (A, C)]
for ex1, ex2 in edges:
ex1.__cause__ = ex2
ex2.__context__ = ex1
raise C
except:
return sys.exc_info()

exc_info_tuple = get_exc_info()

test = Foo('test_1')
result = unittest.TestResult()
result.startTest(test)
result.addFailure(test, exc_info_tuple)
result.stopTest(test)

formatted_exc = result.failures[0][1]
self.assertEqual(formatted_exc.count("Exception: A\n"), 1)
self.assertEqual(formatted_exc.count("Exception: B\n"), 1)
self.assertEqual(formatted_exc.count("Exception: C\n"), 1)

# "addError(test, err)"
# ...
# "Called when the test case test raises an unexpected exception err
Expand Down
4 changes: 3 additions & 1 deletionLib/unittest/result.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -196,6 +196,7 @@ def _clean_tracebacks(self, exctype, value, tb, test):
ret = None
first = True
excs = [(exctype, value, tb)]
seen = {id(value)} # Handle loops in __cause__ or __context__.
while excs:
(exctype, value, tb) = excs.pop()
# Skip test runner traceback levels
Expand All@@ -214,8 +215,9 @@ def _clean_tracebacks(self, exctype, value, tb, test):

if value is not None:
for c in (value.__cause__, value.__context__):
if c is not None andc isnotvalue:
if c is not None andid(c)notin seen:
excs.append((type(c), c, c.__traceback__))
seen.add(id(c))
return ret

def _is_relevant_tb_level(self, tb):
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp