Skip to content

Commit 0588ae6

Browse files
gh-69370: Fix "python -m inspect --details" for unencodable paths
It failed with UnicodeEncodeError if the path of the module contains characters unencodable in the encoding of sys.stdout, e.g. undecodable bytes of a file name. Such characters are now escaped with backslashes, unless stdout uses an error handler which can handle them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 1d90627 commit 0588ae6

3 files changed

Lines changed: 26 additions & 1 deletion

File tree

Lib/inspect.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3461,6 +3461,11 @@ def _main():
34613461
import argparse
34623462
import importlib
34633463

3464+
# The printed text can contain characters unencodable in the encoding
3465+
# of stdout, e.g. undecodable bytes of a file name.
3466+
if getattr(sys.stdout, 'errors', None) == 'strict':
3467+
sys.stdout.reconfigure(errors='backslashreplace')
3468+
34643469
parser = argparse.ArgumentParser()
34653470
parser.add_argument(
34663471
'object',

Lib/test/test_inspect/test_inspect.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
from test.support import MISSING_C_DOCSTRINGS, ALWAYS_EQ
4141
from test.support import run_no_yield_async_fn, EqualToForwardRef
4242
from test.support.import_helper import DirsOnSysPath, ready_to_import
43-
from test.support.os_helper import TESTFN, temp_cwd
43+
from test.support.os_helper import TESTFN, TESTFN_UNDECODABLE, temp_cwd
4444
from test.support.script_helper import assert_python_ok, assert_python_failure, kill_python
4545
from test.support import has_subprocess_support
4646
from test import support
@@ -6584,6 +6584,22 @@ def test_error_data(self):
65846584
lines = err.decode().splitlines()
65856585
self.assertEqual(lines, [self.NO_SOURCE_TARGET_ERROR])
65866586

6587+
@unittest.skipUnless(TESTFN_UNDECODABLE,
6588+
'requires undecodable file names')
6589+
def test_details_undecodable_path(self):
6590+
# gh-69370: the path of the module is not encodable in the encoding
6591+
# of stdout.
6592+
with temp_cwd() as test_dir:
6593+
subdir = os.path.join(os.fsencode(test_dir), TESTFN_UNDECODABLE)
6594+
os.mkdir(subdir)
6595+
with open(os.path.join(subdir, b'undecodable_mod.py'), 'w') as f:
6596+
f.write('"""Module docstring."""\n')
6597+
rc, out, err = assert_python_ok('-X', 'utf8=0', '-m', 'inspect',
6598+
'--details', 'undecodable_mod',
6599+
PYTHONPATH=os.fsdecode(subdir))
6600+
self.assertIn(b'Target: undecodable_mod', out)
6601+
self.assertEqual(err, b'')
6602+
65876603
def test_details_option_with_package(self):
65886604
module_name = 'unittest'
65896605
module = importlib.import_module(module_name)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
``python -m inspect --details`` no longer fails with
2+
:exc:`UnicodeEncodeError` if the path of the module contains characters
3+
unencodable in the encoding of :data:`sys.stdout`. Such characters are now
4+
escaped with backslashes.

0 commit comments

Comments
 (0)