Skip to content

Remove deprecated py3compat module and inline its utilities#15292

Open
Carreau wants to merge 3 commits into
mainfrom
claude/py3compat-cleanup-tjlbpz
Open

Remove deprecated py3compat module and inline its utilities#15292
Carreau wants to merge 3 commits into
mainfrom
claude/py3compat-cleanup-tjlbpz

Conversation

@Carreau

@Carreau Carreau commented Jul 7, 2026

Copy link
Copy Markdown
Member

This PR removes the deprecated IPython/utils/py3compat.py module and inlines its utility functions throughout the codebase. The py3compat module was primarily designed for Python 2/3 compatibility, which is no longer needed as IPython now requires Python 3.

Summary

The py3compat module contained several compatibility utilities that are no longer necessary in a Python 3-only codebase. Rather than maintaining this deprecated module, its functionality has been directly integrated into the modules that use it.

Key Changes

  • Removed IPython/utils/py3compat.py entirely
  • Inlined safe_unicode() logic in IPython/core/interactiveshell.py - replaced with direct try/except handling of str(), repr(), and fallback string
  • Inlined execfile() logic in IPython/core/interactiveshell.py and tests/test_debugger.py - replaced with direct file reading and exec() calls
  • Replaced cast_unicode() calls in IPython/lib/clipboard.py and IPython/core/tbtools.py with inline conditional checks and .decode() calls
  • Replaced decode() calls in IPython/lib/clipboard.py, IPython/testing/tools.py, and IPython/utils/_process_common.py with direct .decode(DEFAULT_ENCODING, "replace") calls
  • Replaced encode() calls in IPython/testing/tools.py with direct .encode(DEFAULT_ENCODING, "replace") calls
  • Replaced input() wrapper in IPython/lib/demo.py, IPython/core/page.py, IPython/lib/editorhooks.py, and IPython/terminal/magics.py with builtin input()
  • Replaced PYPY constant in IPython/lib/pretty.py with inline platform.python_implementation() == "PyPy" check
  • Updated imports across all affected modules to remove py3compat references and import DEFAULT_ENCODING from IPython.utils.encoding where needed

Implementation Details

All inlined code maintains the same error handling and fallback behavior as the original utility functions. The DEFAULT_ENCODING constant is imported from IPython.utils.encoding where needed for encoding/decoding operations.

https://claude.ai/code/session_01NyXpP8SsNDxTCEKnZ5MpF8

@Carreau Carreau force-pushed the claude/py3compat-cleanup-tjlbpz branch from 43d7ab7 to da56255 Compare July 7, 2026 09:06
Comment thread IPython/core/tbtools.py
Comment on lines +204 to 208
file_str = file or ""
if isinstance(file_str, bytes):
file_str = file_str.decode(util_path.fs_encoding, "replace")
name = util_path.compress_user(file_str)
if lineno is None:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@claude it look like file can never be bytes; remove the conditional; add an assertion at the start of the function.

claude added 3 commits July 7, 2026 09:20
- Delete IPython/utils/py3compat.py which was marked as deprecated
- Replace py3compat.decode() with direct .decode() calls
- Replace py3compat.encode() with direct .encode() calls
- Replace py3compat.cast_unicode() with inline type checks and decoding
- Replace py3compat.input() with builtin input()
- Replace py3compat.safe_unicode() with try/except str() fallback
- Replace py3compat.execfile() with inline exec() or local helpers
- Replace py3compat.PYPY with platform.python_implementation() == 'PyPy'
- Import DEFAULT_ENCODING directly where needed for encoding operations

Files updated:
- IPython/utils/_process_win32.py
- IPython/utils/_process_common.py
- IPython/lib/editorhooks.py
- IPython/lib/demo.py
- IPython/lib/clipboard.py
- IPython/lib/pretty.py
- IPython/core/page.py
- IPython/core/tbtools.py
- IPython/core/interactiveshell.py
- IPython/terminal/magics.py
- IPython/testing/tools.py
- tests/test_debugger.py

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NyXpP8SsNDxTCEKnZ5MpF8
The py3compat removal flattened safe_execfile's exec() call, dropping
the intermediate stack frame that tracebacks (and the doctest_tb_plain
/doctest_tb_sysexit tests) expect to see as "in execfile", and which
tb_offset=2 relies on to skip the right number of frames.
Every call site passes a str filename (co_filename or a traceback
record's filename), matching the str | None type annotation, so the
bytes-decoding branch was dead code left over from cast_unicode().
@Carreau Carreau force-pushed the claude/py3compat-cleanup-tjlbpz branch from ae3c5df to 10101d1 Compare July 7, 2026 09:23
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.

2 participants