Repository navigation
Conversation
Fixes samuelcolvin#157 Assisted-by: OpenAI GPT-6 (Codex)
There was a problem hiding this comment.
All reported issues were addressed across 3 files
Reply to a comment to ask cubic a question or push back. It learns from your replies.
View guided diff | Re-trigger cubic
There was a problem hiding this comment.
🔵 Needs a closer look
It modifies the central _format recursion path used by every debug()/pformat call and adds shared mutable state on the module-level singleton, so a human should confirm the broad formatting impact despite no defects being found.
No open issues 🎉
What changed in this PR
This PR fixes issue #157, where debug() / PrettyFormat could exhaust the recursion limit when formatting an object that references itself (directly or mutually). The fix tracks the object identities currently on the active formatting path and renders a repeated ancestor as <Recursion on TYPE> instead of re-expanding it, then continues formatting the remaining fields.
The implementation splits the existing _format into a thin guard (_format) plus the original body (_format_value). The guard records id(value) in a per-instance _active_ids set before recursing and removes it in a finally, so shared (non-ancestor) children still format normally in each branch and formatting errors don't leave stale state. Because the id set is shared across the existing reentrant-stream mechanism, recursion triggered from within a __repr__ is also handled.
Changes:
- Add active-path identity tracking in
PrettyFormat._format, emitting<Recursion on TYPE>for repeated ancestors and cleaning up viafinally. - Add
docs/usage.mdnote describing the new recursion handling. - Add
tests/test_recursion.pywith 12 tests covering self/mutual cycles, dataclasses (with/without slots),__pretty__, generators, reentrant__repr__, shared children, error recovery, anddebug.format().
| File | Description |
|---|---|
devtools/prettier.py |
Introduces _active_ids guard in _format and extracts the formatting body into _format_value to break circular-reference recursion. |
tests/test_recursion.py |
New test module validating recursion rendering across containers, dataclasses, __pretty__, generators, reentrancy, shared children, and error recovery. |
docs/usage.md |
Documents that circular references render as <Recursion on TYPE> while other fields and shared objects still format normally. |
Review effort: Balanced
Assisted-by: OpenAI GPT-6 (Codex)
There was a problem hiding this comment.
All reported issues were addressed across 2 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
Assisted-by: OpenAI GPT-6 (Codex)
Fixes #157. Formatting a dictionary or other expanded object that points back to itself can exhaust the recursion limit and prevent
debug()from showing its contents.Track object identities only along the active formatting path. Render a repeated ancestor as
<Recursion on TYPE>, then continue with the remaining fields. Remove identities infinally, so shared children are formatted normally in each branch and formatting errors do not leave stale state. The same tracking handles reentrant calls from__repr__without changing the existing stream restoration.Adds documentation and 12 tests covering self/mutual container cycles, dataclasses with and without slots,
__pretty__, a self-yielding generator, reentrant__repr__, repeated shared children, recovery after an exception anddebug.format().Validation on Windows:
git diff --checkpassed.The inherited
NO_COLORenvironment variable causes the existingtest_print_is_ttyto fail on both base and patched code. The full-suite results above omit only that variable from the test subprocess environment; repository settings and tests are unchanged. The hosted OS/Python CI matrix remains to be verified.No new dependencies, credentials, network/API calls in the new tests, or changes to workflows/security checks.
AI disclosure: Codex investigated the issue, implemented the change and tests, reviewed the diff, and ran the validation above.
Summary by cubic
Fixes recursive objects causing an infinite recursion error in
debug()andPrettyFormat. Repeated ancestors are now rendered as<Recursion on TYPE>and formatting continues with the remaining fields.finallyso shared children format normally in each branch and errors don't leave stale state.__repr__, containers, dataclasses,__pretty__, and generators; values withinsimple_cutoffkeep Python's compact...recursion notation.Written for commit 9b2da78. Summary will update on new commits.