From 057e541c61ea1b2381cda1484053e3dedfc34393 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Fri, 12 Apr 2024 13:20:29 +0100 Subject: [PATCH 1/4] gh-117786: Fix venv created from Windows Store install by restoring __PYVENV_LAUNCHER__ smuggling --- .../Windows/2024-04-12-13-18-42.gh-issue-117786.LpI01s.rst | 2 ++ PC/venvlauncher.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2024-04-12-13-18-42.gh-issue-117786.LpI01s.rst diff --git a/Misc/NEWS.d/next/Windows/2024-04-12-13-18-42.gh-issue-117786.LpI01s.rst b/Misc/NEWS.d/next/Windows/2024-04-12-13-18-42.gh-issue-117786.LpI01s.rst new file mode 100644 index 00000000000000..a4cd9a9adb3e59 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2024-04-12-13-18-42.gh-issue-117786.LpI01s.rst @@ -0,0 +1,2 @@ +Fixes virtual environments not correctly launching when created from a Store +install. diff --git a/PC/venvlauncher.c b/PC/venvlauncher.c index fe97d32e93b5f6..b1c8d0763d8c76 100644 --- a/PC/venvlauncher.c +++ b/PC/venvlauncher.c @@ -484,8 +484,8 @@ process(int argc, wchar_t ** argv) // We do not update argv[0] to point at the target runtime, and so we do not // pass through our original argv[0] in an environment variable. - //exitCode = smuggle_path(); - //if (exitCode) return exitCode; + exitCode = smuggle_path(); + if (exitCode) return exitCode; exitCode = launch(home_path, GetCommandLineW()); return exitCode; From 29b20efe880c3c852608dec0220a37d78b640492 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Fri, 12 Apr 2024 15:38:57 +0100 Subject: [PATCH 2/4] Use real_executable when launched by launcher --- Lib/test/test_embed.py | 3 +++ Modules/getpath.py | 21 +++++++++++---------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index ec928f935655f9..70c5750251cbc7 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -747,6 +747,9 @@ def check_config(self, configs, expected): if value is self.IGNORE_CONFIG: config.pop(key, None) del expected[key] + # Resolve bool/int mismatches to reduce noise in diffs + if isinstance(value, (bool, int)) and isinstance(config.get(key), (bool, int)): + expected[key] = int(expected[key]) self.assertEqual(config, expected) def check_global_config(self, configs): diff --git a/Modules/getpath.py b/Modules/getpath.py index 1410ffdbed8c70..106f60db97cd5c 100644 --- a/Modules/getpath.py +++ b/Modules/getpath.py @@ -310,7 +310,7 @@ def search_up(prefix, *landmarks, test=isfile): # and should not affect base_executable. base_executable = f"{dirname(library)}/bin/python{VERSION_MAJOR}.{VERSION_MINOR}" else: - base_executable = executable + base_executable = real_executable if not real_executable: real_executable = base_executable @@ -408,13 +408,14 @@ def search_up(prefix, *landmarks, test=isfile): if not real_executable: real_executable = base_executable -try: - real_executable = realpath(real_executable) -except OSError as ex: - # Only warn if the file actually exists and was unresolvable - # Otherwise users who specify a fake executable may get spurious warnings. - if isfile(real_executable): - warn(f'Failed to find real location of {base_executable}') +if real_executable: + try: + real_executable = realpath(real_executable) + except OSError as ex: + # Only warn if the file actually exists and was unresolvable + # Otherwise users who specify a fake executable may get spurious warnings. + if isfile(real_executable): + warn(f'Failed to find real location of {base_executable}') if not executable_dir and os_name == 'darwin' and library: # QUIRK: macOS checks adjacent to its library early @@ -427,12 +428,12 @@ def search_up(prefix, *landmarks, test=isfile): # If we do not have the executable's directory, we can calculate it. # This is the directory used to find prefix/exec_prefix if necessary. -if not executable_dir: +if not executable_dir and real_executable: executable_dir = real_executable_dir = dirname(real_executable) # If we do not have the real executable's directory, we calculate it. # This is the directory used to detect build layouts. -if not real_executable_dir: +if not real_executable_dir and real_executable: real_executable_dir = dirname(real_executable) # ****************************************************************************** From bb3ca988abe08abaa7909c8d648a32b1d0bc2576 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Fri, 12 Apr 2024 15:50:48 +0100 Subject: [PATCH 3/4] Clarifying comment --- Modules/getpath.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Modules/getpath.py b/Modules/getpath.py index 106f60db97cd5c..bc7053224aaf16 100644 --- a/Modules/getpath.py +++ b/Modules/getpath.py @@ -310,7 +310,10 @@ def search_up(prefix, *landmarks, test=isfile): # and should not affect base_executable. base_executable = f"{dirname(library)}/bin/python{VERSION_MAJOR}.{VERSION_MINOR}" else: - base_executable = real_executable + # Use the real executable as our base, or argv[0] otherwise + # (on Windows, argv[0] is likely to be ENV___PYVENV_LAUNCHER__; on + # other platforms, real_executable is likely to be empty) + base_executable = real_executable or executable if not real_executable: real_executable = base_executable From 2bda84a3becd58619b8cf5466252769ee3cda651 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Mon, 15 Apr 2024 17:04:41 +0100 Subject: [PATCH 4/4] Update Lib/test/test_embed.py --- Lib/test/test_embed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 70c5750251cbc7..d94c63a13b8ea4 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -749,7 +749,7 @@ def check_config(self, configs, expected): del expected[key] # Resolve bool/int mismatches to reduce noise in diffs if isinstance(value, (bool, int)) and isinstance(config.get(key), (bool, int)): - expected[key] = int(expected[key]) + expected[key] = type(config[key])(expected[key]) self.assertEqual(config, expected) def check_global_config(self, configs):