Return the index of the frame/TracebackEntry where recursion originates if appropriate, None if no recursion occurred.
(self)
| 444 | return Traceback(filter(fn, self)) |
| 445 | |
| 446 | def recursionindex(self) -> int | None: |
| 447 | """Return the index of the frame/TracebackEntry where recursion originates if |
| 448 | appropriate, None if no recursion occurred.""" |
| 449 | cache: dict[tuple[Any, int, int], list[dict[str, Any]]] = {} |
| 450 | for i, entry in enumerate(self): |
| 451 | # id for the code.raw is needed to work around |
| 452 | # the strange metaprogramming in the decorator lib from pypi |
| 453 | # which generates code objects that have hash/value equality |
| 454 | # XXX needs a test |
| 455 | key = entry.frame.code.path, id(entry.frame.code.raw), entry.lineno |
| 456 | values = cache.setdefault(key, []) |
| 457 | # Since Python 3.13 f_locals is a proxy, freeze it. |
| 458 | loc = dict(entry.frame.f_locals) |
| 459 | if values: |
| 460 | for otherloc in values: |
| 461 | if otherloc == loc: |
| 462 | return i |
| 463 | values.append(loc) |
| 464 | return None |
| 465 | |
| 466 | |
| 467 | def stringify_exception( |