https://github.com/python/cpython/commit/fa7212b0af1c3d4e0cf8ac2ead35df3541436fb4
commit: fa7212b0af1c3d4e0cf8ac2ead35df3541436fb4
branch: 3.14
author: Miss Islington (bot) <[email protected]>
committer: zooba <[email protected]>
date: 2026-03-06T10:22:29Z
summary:

[3.14] gh-122941: Fix test_launcher sporadic failures via py.ini isolation 
(GH-145090)

Adds _PYLAUNCHER_INIDIR as a private variable since the launcher is deprecated 
and not getting new features.
(cherry picked from commit 6cdbd7bc5d4ee63459d03a944477ea8671a05198)

Co-authored-by: Itamar Oren <[email protected]>

files:
M Lib/test/test_launcher.py
M PC/launcher2.c

diff --git a/Lib/test/test_launcher.py b/Lib/test/test_launcher.py
index caa1603c78eb01..c522bc1c2c093c 100644
--- a/Lib/test/test_launcher.py
+++ b/Lib/test/test_launcher.py
@@ -227,6 +227,8 @@ def run_py(self, args, env=None, allow_fail=False, 
expect_returncode=0, argv=Non
             "PYLAUNCHER_LIMIT_TO_COMPANY": "",
             **{k.upper(): v for k, v in (env or {}).items()},
         }
+        if ini_dir := getattr(self, '_ini_dir', None):
+            env.setdefault("_PYLAUNCHER_INIDIR", ini_dir)
         if not argv:
             argv = [self.py_exe, *args]
         with subprocess.Popen(
@@ -262,11 +264,14 @@ def run_py(self, args, env=None, allow_fail=False, 
expect_returncode=0, argv=Non
         return data
 
     def py_ini(self, content):
-        local_appdata = os.environ.get("LOCALAPPDATA")
-        if not local_appdata:
-            raise unittest.SkipTest("LOCALAPPDATA environment variable is "
-                                    "missing or empty")
-        return PreservePyIni(Path(local_appdata) / "py.ini", content)
+        ini_dir = getattr(self, '_ini_dir', None)
+        if not ini_dir:
+            local_appdata = os.environ.get("LOCALAPPDATA")
+            if not local_appdata:
+                raise unittest.SkipTest("LOCALAPPDATA environment variable is "
+                                        "missing or empty")
+            ini_dir = local_appdata
+        return PreservePyIni(Path(ini_dir) / "py.ini", content)
 
     @contextlib.contextmanager
     def script(self, content, encoding="utf-8"):
@@ -302,6 +307,8 @@ def setUpClass(cls):
             p = subprocess.check_output("reg query HKCU\\Software\\Python /s")
             #print(p.decode('mbcs'))
 
+        cls._ini_dir = tempfile.mkdtemp()
+        cls.addClassCleanup(shutil.rmtree, cls._ini_dir, ignore_errors=True)
 
     @classmethod
     def tearDownClass(cls):
diff --git a/PC/launcher2.c b/PC/launcher2.c
index 832935c5cc6c1c..4dd18c8eb5462e 100644
--- a/PC/launcher2.c
+++ b/PC/launcher2.c
@@ -922,6 +922,20 @@ _readIni(const wchar_t *section, const wchar_t 
*settingName, wchar_t *buffer, in
 {
     wchar_t iniPath[MAXLEN];
     int n;
+    // Check for _PYLAUNCHER_INIDIR override (used for test isolation)
+    DWORD len = GetEnvironmentVariableW(L"_PYLAUNCHER_INIDIR", iniPath, 
MAXLEN);
+    if (len && len < MAXLEN) {
+        if (join(iniPath, MAXLEN, L"py.ini")) {
+            debug(L"# Reading from %s for %s/%s\n", iniPath, section, 
settingName);
+            n = GetPrivateProfileStringW(section, settingName, NULL, buffer, 
bufferLength, iniPath);
+            if (n) {
+                debug(L"# Found %s in %s\n", settingName, iniPath);
+                return n;
+            }
+        }
+        // When _PYLAUNCHER_INIDIR is set, skip the default locations
+        return 0;
+    }
     if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, 
iniPath)) &&
         join(iniPath, MAXLEN, L"py.ini")) {
         debug(L"# Reading from %s for %s/%s\n", iniPath, section, settingName);

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to