diff --git a/Lib/inspect.py b/Lib/inspect.py index 2a14e43b66f2fac..d18d39ae74be9b7 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -3461,6 +3461,10 @@ def _main(): import argparse import importlib + # The printed text can contain characters unencodable in the encoding + # of stdout, e.g. undecodable bytes of a file name. + sys.stdout.reconfigure(errors='backslashreplace') + parser = argparse.ArgumentParser() parser.add_argument( 'object', diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 5153e5eb9a4ff8b..7ded4b2b2971928 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -40,7 +40,7 @@ from test.support import MISSING_C_DOCSTRINGS, ALWAYS_EQ from test.support import run_no_yield_async_fn, EqualToForwardRef from test.support.import_helper import DirsOnSysPath, ready_to_import -from test.support.os_helper import TESTFN, temp_cwd +from test.support.os_helper import TESTFN, TESTFN_UNDECODABLE, temp_cwd from test.support.script_helper import assert_python_ok, assert_python_failure, kill_python from test.support import has_subprocess_support from test import support @@ -6584,6 +6584,25 @@ def test_error_data(self): lines = err.decode().splitlines() self.assertEqual(lines, [self.NO_SOURCE_TARGET_ERROR]) + @unittest.skipUnless(TESTFN_UNDECODABLE, + 'requires undecodable file names') + def test_details_undecodable_path(self): + # gh-69370: the path of the module is not encodable in the encoding + # of stdout. + with temp_cwd() as test_dir: + subdir = os.path.join(os.fsencode(test_dir), TESTFN_UNDECODABLE) + try: + os.mkdir(subdir) + except OSError: + self.skipTest('undecodable paths are not supported') + with open(os.path.join(subdir, b'undecodable_mod.py'), 'w') as f: + f.write('"""Module docstring."""\n') + rc, out, err = assert_python_ok('-X', 'utf8=0', '-m', 'inspect', + '--details', 'undecodable_mod', + PYTHONPATH=os.fsdecode(subdir)) + self.assertIn(b'Target: undecodable_mod', out) + self.assertEqual(err, b'') + def test_details_option_with_package(self): module_name = 'unittest' module = importlib.import_module(module_name) diff --git a/Misc/NEWS.d/next/Library/2026-08-05-17-30-00.gh-issue-69370.inspCLI.rst b/Misc/NEWS.d/next/Library/2026-08-05-17-30-00.gh-issue-69370.inspCLI.rst new file mode 100644 index 000000000000000..27c97f9bdf07b48 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-08-05-17-30-00.gh-issue-69370.inspCLI.rst @@ -0,0 +1,4 @@ +:program:`python -m inspect --details` no longer fails with +:exc:`UnicodeEncodeError` if the path of the module contains characters +unencodable in the encoding of :data:`sys.stdout`. Such characters are now +escaped with backslashes.