From 58eb3f28988763ce1e9dfb395c3f2aaf44307847 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 10 Jun 2026 15:19:12 +0200 Subject: [PATCH 1/3] gh-151253: Dump the path config if "import encodings" fails If "import encodings" fails at Python startup, dump the Python path configuration to help users debugging their configuration. The encodings module is the first module imported during Python startup. --- .../2026-06-10-15-42-46.gh-issue-151253.7MMQ8P.rst | 3 +++ Python/codecs.c | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-10-15-42-46.gh-issue-151253.7MMQ8P.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-10-15-42-46.gh-issue-151253.7MMQ8P.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-10-15-42-46.gh-issue-151253.7MMQ8P.rst new file mode 100644 index 000000000000000..56d2f3b2633bb01 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-10-15-42-46.gh-issue-151253.7MMQ8P.rst @@ -0,0 +1,3 @@ +If ``import encodings`` (first import) fails at Python startup, dump the +Python path configuration to help users debugging their configuration. Patch +by Victor Stinner. diff --git a/Python/codecs.c b/Python/codecs.c index a522e6b88068b3e..6d1ae651fa00058 100644 --- a/Python/codecs.c +++ b/Python/codecs.c @@ -11,6 +11,7 @@ Copyright (c) Corporation for National Research Initiatives. #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_codecs.h" // export _PyCodec_LookupTextEncoding() +#include "pycore_initconfig.h" // _Py_DumpPathConfig() #include "pycore_interp.h" // PyInterpreterState.codec_search_path #include "pycore_pyerrors.h" // _PyErr_FormatNote() #include "pycore_pystate.h" // _PyInterpreterState_GET() @@ -1686,6 +1687,8 @@ _PyCodec_InitRegistry(PyInterpreterState *interp) // search functions, so this is done after everything else is initialized. PyObject *mod = PyImport_ImportModule("encodings"); if (mod == NULL) { + PyThreadState *tstate = _PyThreadState_GET(); + _Py_DumpPathConfig(tstate); return PyStatus_Error("Failed to import encodings module"); } Py_DECREF(mod); From ded830267aad9c90b50ab3892b3fed482991d743 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 10 Jun 2026 15:47:46 +0200 Subject: [PATCH 2/3] Add unit test --- Lib/test/test_cmd_line.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py index 3b556ec31445dfb..3caa4a001937a3e 100644 --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -1314,6 +1314,14 @@ def test_presite(self): proc = assert_python_ok("-X", f"presite={entrypoint}", "-c", "pass") self.assertEqual(proc.out.rstrip(), b"presite func") + def test_dump_path_config(self): + # gh-151253: At the first import (import encodings) during Python + # startup, if the import fails, dump the Python path configuration. + nonexistent = '/nonexistent-python-path' + proc = assert_python_failure("-c", "pass", PYTHONHOME=nonexistent) + self.assertIn(b'Python path configuration:', proc.err) + self.assertIn(f"PYTHONHOME = '{nonexistent}'".encode(), proc.err) + @unittest.skipIf(interpreter_requires_environment(), 'Cannot run -I tests when PYTHON env vars are required.') From 1b227a777dca7482a508fd5501303c678883be2e Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 10 Jun 2026 17:15:53 +0200 Subject: [PATCH 3/3] Use -X frozen_modules=off in the test --- Lib/test/test_cmd_line.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py index 3caa4a001937a3e..a8645af26b25d87 100644 --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -1318,7 +1318,10 @@ def test_dump_path_config(self): # gh-151253: At the first import (import encodings) during Python # startup, if the import fails, dump the Python path configuration. nonexistent = '/nonexistent-python-path' - proc = assert_python_failure("-c", "pass", PYTHONHOME=nonexistent) + # Use -X frozen_modules=off to disable frozen encodings module + # on release build. + cmd = ["-X", "frozen_modules=off", "-c", "pass"] + proc = assert_python_failure(*cmd, PYTHONHOME=nonexistent) self.assertIn(b'Python path configuration:', proc.err) self.assertIn(f"PYTHONHOME = '{nonexistent}'".encode(), proc.err)