Skip to content

Fix RuntimeError when pretty-printing a dict mutated during iteration - #15471

Open
SakthivelMadhu wants to merge 1 commit into
ipython:mainfrom
SakthivelMadhu:fix-14541-dict-pretty-mutation
Open

SakthivelMadhu wants to merge 1 commit into
ipython:mainfrom
SakthivelMadhu:fix-14541-dict-pretty-mutation

Conversation

@SakthivelMadhu

Copy link
Copy Markdown

Problem

On the first vars(posix) call, IPython raises
RuntimeError: dictionary changed size during iteration.

Root cause

_dict_pprinter_factory iterates over the live obj.keys() view. While the
values are being printed, the module's __dict__ gains __builtins__, so the
dict changes size mid-iteration. On later calls the key already exists, which is
why only the first call fails.

Fix

Snapshot the keys with list(obj.keys()) before iterating. The output reflects
the dict as it was when printing started.

Why not catch the error and retry: retrying hides the mutation and can loop;
a snapshot is deterministic. Cost is O(n) extra memory for the key list.

Tests

Added test_dict_mutated_during_pretty_printing, which mutates the dict from
inside a value's __repr__.

Before After
New test ❌ RuntimeError ✅ pass
import posix; vars(posix) Same code path as the new test (not run directly: tested on Windows, where posix is unavailable) Covered by the new test
tests/test_pretty.py, tests/test_formatters.py ✅ ✅ 86 passed, 1 skipped

Closes #14541

Snapshot dict keys before iterating in _dict_pprinter_factory so that
printing a value which mutates the dict (e.g. a module __dict__ gaining
__builtins__ on first vars(posix)) no longer raises.

Closes ipython#14541

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RuntimeError on first call to vars(posix)

1 participant