From 08846b2c6f6c72c86f764bc07767ef9d49bad742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Thu, 26 Feb 2026 20:52:02 +0000 Subject: [PATCH 1/7] GH-145273: warn when we can't find the standard library MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filipe Laíns --- ...-02-26-20-51-54.gh-issue-145273.B5QcUp.rst | 2 ++ Modules/getpath.py | 23 ++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-02-26-20-51-54.gh-issue-145273.B5QcUp.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-02-26-20-51-54.gh-issue-145273.B5QcUp.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-26-20-51-54.gh-issue-145273.B5QcUp.rst new file mode 100644 index 00000000000000..8d9e4a872d0d7a --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-26-20-51-54.gh-issue-145273.B5QcUp.rst @@ -0,0 +1,2 @@ +A warning is now shown during :ref:`sys-path-init` if it can't find a valid +standard library. diff --git a/Modules/getpath.py b/Modules/getpath.py index ceb605a75c85f4..e06297b7b63a7b 100644 --- a/Modules/getpath.py +++ b/Modules/getpath.py @@ -236,6 +236,7 @@ def search_up(prefix, *landmarks, test=isfile): real_executable_dir = None platstdlib_dir = None +stdlib_zip = None # ****************************************************************************** # CALCULATE program_name @@ -697,12 +698,13 @@ def search_up(prefix, *landmarks, test=isfile): library_dir = dirname(library) else: library_dir = executable_dir - pythonpath.append(joinpath(library_dir, ZIP_LANDMARK)) + stdlib_zip = joinpath(library_dir, ZIP_LANDMARK) elif build_prefix: # QUIRK: POSIX uses the default prefix when in the build directory - pythonpath.append(joinpath(PREFIX, ZIP_LANDMARK)) + stdlib_zip = joinpath(PREFIX, ZIP_LANDMARK) else: - pythonpath.append(joinpath(base_prefix, ZIP_LANDMARK)) + stdlib_zip = joinpath(base_prefix, ZIP_LANDMARK) + pythonpath.append(stdlib_zip) if os_name == 'nt' and use_environment and winreg: # QUIRK: Windows also lists paths in the registry. Paths are stored @@ -767,6 +769,21 @@ def search_up(prefix, *landmarks, test=isfile): config['module_search_paths_set'] = 1 +# ****************************************************************************** +# SANITY CHECKS +# ****************************************************************************** + +# Warn if the standard library is missing +if not stdlib_zip or not isfile(stdlib_zip): + home_hint = f"The Python 'home' directory was set to {home!r}, is this correct?" + if not stdlib_dir or not isdir(stdlib_dir): + hint = home_hint if home else f'sys.prefix is set to {prefix}, is this correct?' + warn('WARN: Could not find the standard library directory! ' + hint) + elif (not platstdlib_dir and not build_prefix) or not isdir(platstdlib_dir): + hint = home_hint if home else f'sys.exec_prefix is set to {exec_prefix}, is this correct?' + warn('WARN: Could not find the platform standard library directory! ' + hint) + + # ****************************************************************************** # POSIX prefix/exec_prefix QUIRKS # ****************************************************************************** From d38285df901d98c08e1db76fd6a7ae021baced24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Thu, 26 Feb 2026 22:19:51 +0000 Subject: [PATCH 2/7] Fix test_embed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filipe Laíns --- Lib/test/test_embed.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 35246d7c484439..c8d2816b2d98cb 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -1492,7 +1492,8 @@ def test_init_setpythonhome(self): self.default_program_name(config) env = {'TESTHOME': home, 'PYTHONPATH': paths_str} self.check_all_configs("test_init_setpythonhome", config, - api=API_COMPAT, env=env) + api=API_COMPAT, env=env, + ignore_stderr=True) # ignore missing stdlib warning def test_init_is_python_build_with_home(self): # Test _Py_path_config._is_python_build configuration (gh-91985) @@ -1536,7 +1537,8 @@ def test_init_is_python_build_with_home(self): env['NEGATIVE_ISPYTHONBUILD'] = '1' config['_is_python_build'] = 0 self.check_all_configs("test_init_is_python_build", config, - api=API_COMPAT, env=env) + api=API_COMPAT, env=env, + ignore_stderr=True) # ignore missing stdlib warning env['NEGATIVE_ISPYTHONBUILD'] = '0' config['_is_python_build'] = 1 @@ -1552,7 +1554,8 @@ def test_init_is_python_build_with_home(self): config.update(prefix=prefix, base_prefix=prefix, exec_prefix=exec_prefix, base_exec_prefix=exec_prefix) self.check_all_configs("test_init_is_python_build", config, - api=API_COMPAT, env=env) + api=API_COMPAT, env=env, + ignore_stderr=True) # ignore missing stdlib warning) def copy_paths_by_env(self, config): all_configs = self._get_expected_config() From c55803d035b05e736833a8198a19fb61837da3c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Thu, 26 Feb 2026 23:46:52 +0000 Subject: [PATCH 3/7] Create stdlib dir on test_init_pybuilddir{,_win32} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filipe Laíns --- Lib/test/test_embed.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index c8d2816b2d98cb..f61ca58a743f9a 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -1555,7 +1555,7 @@ def test_init_is_python_build_with_home(self): exec_prefix=exec_prefix, base_exec_prefix=exec_prefix) self.check_all_configs("test_init_is_python_build", config, api=API_COMPAT, env=env, - ignore_stderr=True) # ignore missing stdlib warning) + ignore_stderr=True) # ignore missing stdlib warning def copy_paths_by_env(self, config): all_configs = self._get_expected_config() @@ -1578,6 +1578,8 @@ def test_init_pybuilddir(self): # The stdlib dir is dirname(executable) + VPATH + 'Lib' stdlibdir = os.path.normpath(os.path.join(tmpdir, vpath, 'Lib')) os.mkdir(libdir) + # Create the directory to avoid the bad stdlib dir warning + os.makedirs(stdlibdir) filename = os.path.join(tmpdir, 'pybuilddir.txt') with open(filename, "w", encoding="utf8") as fp: @@ -1616,6 +1618,9 @@ def test_init_pybuilddir_win32(self): # The stdlib dir is dirname(executable) + VPATH + 'Lib' stdlibdir = os.path.normpath(os.path.join(tmpdir, vpath, 'Lib')) + # Create the directory to avoid the bad stdlib dir warning + os.makedirs(stdlibdir) + filename = os.path.join(tmpdir, 'pybuilddir.txt') with open(filename, "w", encoding="utf8") as fp: fp.write(tmpdir) From 3a67467c2a8a927b5ab275aab8d13de0027ea535 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Thu, 26 Feb 2026 23:52:56 +0000 Subject: [PATCH 4/7] Resolve symlinks before file check (needed for Windows) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filipe Laíns --- Modules/getpath.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/getpath.py b/Modules/getpath.py index e06297b7b63a7b..eb5737fe2196cf 100644 --- a/Modules/getpath.py +++ b/Modules/getpath.py @@ -774,12 +774,12 @@ def search_up(prefix, *landmarks, test=isfile): # ****************************************************************************** # Warn if the standard library is missing -if not stdlib_zip or not isfile(stdlib_zip): +if not stdlib_zip or not isfile(realpath(stdlib_zip)): home_hint = f"The Python 'home' directory was set to {home!r}, is this correct?" - if not stdlib_dir or not isdir(stdlib_dir): + if not stdlib_dir or not isdir(realpath(stdlib_dir)): hint = home_hint if home else f'sys.prefix is set to {prefix}, is this correct?' warn('WARN: Could not find the standard library directory! ' + hint) - elif (not platstdlib_dir and not build_prefix) or not isdir(platstdlib_dir): + elif (not platstdlib_dir and not build_prefix) or not isdir(realpath(platstdlib_dir)): hint = home_hint if home else f'sys.exec_prefix is set to {exec_prefix}, is this correct?' warn('WARN: Could not find the platform standard library directory! ' + hint) From aa6014ac56fd5906983d599864e3b9134cfc6a2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Fri, 27 Feb 2026 00:29:54 +0000 Subject: [PATCH 5/7] Revert "Resolve symlinks before file check (needed for Windows)" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 3a67467c2a8a927b5ab275aab8d13de0027ea535. Signed-off-by: Filipe Laíns --- Modules/getpath.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/getpath.py b/Modules/getpath.py index eb5737fe2196cf..e06297b7b63a7b 100644 --- a/Modules/getpath.py +++ b/Modules/getpath.py @@ -774,12 +774,12 @@ def search_up(prefix, *landmarks, test=isfile): # ****************************************************************************** # Warn if the standard library is missing -if not stdlib_zip or not isfile(realpath(stdlib_zip)): +if not stdlib_zip or not isfile(stdlib_zip): home_hint = f"The Python 'home' directory was set to {home!r}, is this correct?" - if not stdlib_dir or not isdir(realpath(stdlib_dir)): + if not stdlib_dir or not isdir(stdlib_dir): hint = home_hint if home else f'sys.prefix is set to {prefix}, is this correct?' warn('WARN: Could not find the standard library directory! ' + hint) - elif (not platstdlib_dir and not build_prefix) or not isdir(realpath(platstdlib_dir)): + elif (not platstdlib_dir and not build_prefix) or not isdir(platstdlib_dir): hint = home_hint if home else f'sys.exec_prefix is set to {exec_prefix}, is this correct?' warn('WARN: Could not find the platform standard library directory! ' + hint) From 540d965a58ae6651376ae6332d49c955b324e77a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Fri, 27 Feb 2026 01:09:01 +0000 Subject: [PATCH 6/7] Fix test.support.PythonSymlink on Windows source builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filipe Laíns --- Lib/test/support/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 307bac65ae50a8..d4d3c7f1aefa66 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -1716,9 +1716,10 @@ def _platform_specific(self): )) self._env = {k.upper(): os.getenv(k) for k in os.environ} - self._env["PYTHONHOME"] = os.path.dirname(self.real) + home = os.path.dirname(self.real) if sysconfig.is_python_build(): - self._env["PYTHONPATH"] = STDLIB_DIR + home = os.path.join(home, sysconfig.get_config_var('VPATH')) + self._env["PYTHONHOME"] = home else: def _platform_specific(self): pass From 9cb1166493fc5b0116c5e96bc56becc2e98c2bc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Fri, 27 Feb 2026 01:36:55 +0000 Subject: [PATCH 7/7] Fix test_embed by creating expected paths instead of ignoring stderr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filipe Laíns --- Lib/test/test_embed.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index f61ca58a743f9a..a8ff40222ae46a 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -1479,6 +1479,10 @@ def test_init_setpythonhome(self): stdlib = os.path.join(home, sys.platlibdir, f'python{version}{ABI_THREAD}') expected_paths = self.module_search_paths(prefix=home, exec_prefix=home) + # Create the expected paths to avoid the bad stdlib dir warning + for entry in expected_paths: + os.makedirs(entry, exist_ok=True) + config = { 'home': home, 'module_search_paths': expected_paths, @@ -1492,8 +1496,7 @@ def test_init_setpythonhome(self): self.default_program_name(config) env = {'TESTHOME': home, 'PYTHONPATH': paths_str} self.check_all_configs("test_init_setpythonhome", config, - api=API_COMPAT, env=env, - ignore_stderr=True) # ignore missing stdlib warning + api=API_COMPAT, env=env) def test_init_is_python_build_with_home(self): # Test _Py_path_config._is_python_build configuration (gh-91985) @@ -1521,6 +1524,10 @@ def test_init_is_python_build_with_home(self): stdlib = os.path.join(home, sys.platlibdir, f'python{version}{ABI_THREAD}') expected_paths = self.module_search_paths(prefix=home, exec_prefix=home) + # Create the expected paths to avoid the bad stdlib dir warning + for entry in expected_paths: + os.makedirs(entry, exist_ok=True) + config = { 'home': home, 'module_search_paths': expected_paths, @@ -1537,8 +1544,7 @@ def test_init_is_python_build_with_home(self): env['NEGATIVE_ISPYTHONBUILD'] = '1' config['_is_python_build'] = 0 self.check_all_configs("test_init_is_python_build", config, - api=API_COMPAT, env=env, - ignore_stderr=True) # ignore missing stdlib warning + api=API_COMPAT, env=env) env['NEGATIVE_ISPYTHONBUILD'] = '0' config['_is_python_build'] = 1 @@ -1554,8 +1560,7 @@ def test_init_is_python_build_with_home(self): config.update(prefix=prefix, base_prefix=prefix, exec_prefix=exec_prefix, base_exec_prefix=exec_prefix) self.check_all_configs("test_init_is_python_build", config, - api=API_COMPAT, env=env, - ignore_stderr=True) # ignore missing stdlib warning + api=API_COMPAT, env=env) def copy_paths_by_env(self, config): all_configs = self._get_expected_config()