https://github.com/python/cpython/commit/90bf681df19b734f191a21058ce7b511560d2f8a
commit: 90bf681df19b734f191a21058ce7b511560d2f8a
branch: main
author: Victor Stinner <[email protected]>
committer: vstinner <[email protected]>
date: 2026-05-26T16:33:08Z
summary:

gh-149879: Fix test_embed on Cygwin (#150441)

files:
M Lib/test/test_embed.py
M Programs/_testembed.c

diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py
index c5ced3cc6134b96..2d1533c46b98f33 100644
--- a/Lib/test/test_embed.py
+++ b/Lib/test/test_embed.py
@@ -74,6 +74,27 @@ def debug_build(program):
     return name.casefold().endswith("_d".casefold())
 
 
+def getpath_which(program_name):
+    if sys.platform != 'cygwin':
+        return shutil.which(program_name)
+
+    # shutil.which() checks for os.access(fn, os.F_OK | os.X_OK), whereas
+    # getpath.isxfile() doesn't. The difference matters on Cygwin.
+    import stat
+    def isxfile(fn):
+        try:
+            st = os.stat(fn)
+        except OSError:
+            return False
+        return stat.S_ISREG(st.st_mode)
+
+    for p in os.environ['PATH'].split(':'):
+        p = os.path.join(p, program_name)
+        if isxfile(p):
+            return p
+    return None
+
+
 def remove_python_envvars():
     env = dict(os.environ)
     # Remove PYTHON* environment variables to get deterministic environment
@@ -92,6 +113,8 @@ def setUp(self):
             exename += ext
             exepath = builddir
         else:
+            if sys.platform == 'cygwin':
+                exename += '.exe'
             exepath = os.path.join(builddir, 'Programs')
         self.test_exe = exe = os.path.join(exepath, exename)
         if not os.path.exists(exe):
@@ -328,6 +351,8 @@ def test_pre_initialization_api(self):
             expected_path = self.test_exe
         else:
             expected_path = os.path.join(os.getcwd(), "_testembed")
+            if sys.platform == 'cygwin':
+                expected_path += '.exe'
         expected_output = f"sys.executable: {expected_path}\n"
         self.assertIn(expected_output, out)
         self.assertEqual(err, '')
@@ -872,12 +897,16 @@ def get_expected_config(self, expected_preconfig, 
expected,
             default_executable = os.path.abspath(expected['program_name'])
         else:
             default_executable = os.path.join(os.getcwd(), '_testembed')
+            if sys.platform == 'cygwin':
+                default_executable += '.exe'
         if expected['executable'] is self.GET_DEFAULT_CONFIG:
             expected['executable'] = default_executable
         if expected['base_executable'] is self.GET_DEFAULT_CONFIG:
             expected['base_executable'] = default_executable
         if expected['program_name'] is self.GET_DEFAULT_CONFIG:
             expected['program_name'] = './_testembed'
+            if sys.platform == 'cygwin':
+                expected['program_name'] += '.exe'
 
         config = configs['config']
         for key, value in expected.items():
@@ -1370,7 +1399,7 @@ def default_program_name(self, config):
             if MACOS:
                 executable = self.test_exe
             else:
-                executable = shutil.which(program_name) or ''
+                executable = getpath_which(program_name) or ''
         config.update({
             'program_name': program_name,
             'base_executable': executable,
@@ -1469,6 +1498,13 @@ def tmpdir_with_python(self, subdir=None):
             shutil.copystat(self.test_exe, exec_copy)
             self.test_exe = exec_copy
 
+            if sys.platform == "cygwin":
+                # Copy libpython DLL
+                exe_path = os.path.dirname(sys.executable)
+                libpython_dll = sysconfig.get_config_var('DLLLIBRARY')
+                shutil.copy2(os.path.join(exe_path, libpython_dll),
+                             os.path.join(tmpdir, libpython_dll))
+
             yield tmpdir
 
     def test_init_setpythonhome(self):
diff --git a/Programs/_testembed.c b/Programs/_testembed.c
index 278984ddb17c1a2..7246cc06ffff036 100644
--- a/Programs/_testembed.c
+++ b/Programs/_testembed.c
@@ -41,8 +41,13 @@ char **main_argv;
 #define PROGRAM "test_embed"
 
 /* Use path starting with "./" avoids a search along the PATH */
-#define PROGRAM_NAME L"./_testembed"
-#define PROGRAM_NAME_UTF8 "./_testembed"
+#ifdef __CYGWIN__
+#  define PROGRAM_NAME L"./_testembed.exe"
+#  define PROGRAM_NAME_UTF8 "./_testembed.exe"
+#else
+#  define PROGRAM_NAME L"./_testembed"
+#  define PROGRAM_NAME_UTF8 "./_testembed"
+#endif
 
 #define INIT_LOOPS 4
 

_______________________________________________
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