(first: BaseException, second: BaseException)
| 149 | |
| 150 | |
| 151 | def _same_exception_tree(first: BaseException, second: BaseException) -> bool: |
| 152 | pending = [(first, second)] |
| 153 | seen: set[tuple[int, int]] = set() |
| 154 | while pending: |
| 155 | first_error, second_error = pending.pop() |
| 156 | if first_error is second_error: |
| 157 | continue |
| 158 | if (pair := (id(first_error), id(second_error))) in seen: |
| 159 | continue |
| 160 | seen.add(pair) |
| 161 | if ( |
| 162 | type(first_error) is not type(second_error) |
| 163 | or not isinstance(first_error, _exception_group_cls()) |
| 164 | or not isinstance(second_error, _exception_group_cls()) |
| 165 | ): |
| 166 | return False |
| 167 | first_group = cast("_ExceptionGroupProtocol", first_error) |
| 168 | second_group = cast("_ExceptionGroupProtocol", second_error) |
| 169 | if first_group.message != second_group.message or len(first_group.exceptions) != len(second_group.exceptions): |
| 170 | return False |
| 171 | pending.extend(zip(first_group.exceptions, second_group.exceptions, strict=True)) |
| 172 | return True |
| 173 | |
| 174 | |
| 175 | def _contains_exception(error: BaseException, target: BaseException | None) -> bool: |
no test coverage detected