@@ -192,34 +192,57 @@ def _get_tcl_tk_libs():
192
192
193
193
def _fast_get_system_executable (self ):
194
194
"""Try to get the system executable by just looking at properties."""
195
- if self .real_prefix or ( # noqa: PLR1702
196
- self .base_prefix is not None and self .base_prefix != self .prefix
197
- ): # if this is a virtual environment
198
- if self .real_prefix is None :
199
- base_executable = getattr (sys , "_base_executable" , None ) # some platforms may set this to help us
200
- if base_executable is not None : # noqa: SIM102 # use the saved system executable if present
201
- if sys .executable != base_executable : # we know we're in a virtual environment, cannot be us
202
- if os .path .exists (base_executable ):
203
- return base_executable
204
- # Python may return "python" because it was invoked from the POSIX virtual environment
205
- # however some installs/distributions do not provide a version-less "python" binary in
206
- # the system install location (see PEP 394) so try to fallback to a versioned binary.
207
- #
208
- # Gate this to Python 3.11 as `sys._base_executable` path resolution is now relative to
209
- # the 'home' key from pyvenv.cfg which often points to the system install location.
210
- major , minor = self .version_info .major , self .version_info .minor
211
- if self .os == "posix" and (major , minor ) >= (3 , 11 ):
212
- # search relative to the directory of sys._base_executable
213
- base_dir = os .path .dirname (base_executable )
214
- for base_executable in [
215
- os .path .join (base_dir , exe ) for exe in (f"python{ major } " , f"python{ major } .{ minor } " )
216
- ]:
217
- if os .path .exists (base_executable ):
218
- return base_executable
219
- return None # in this case we just can't tell easily without poking around FS and calling them, bail
220
195
# if we're not in a virtual environment, this is already a system python, so return the original executable
221
196
# note we must choose the original and not the pure executable as shim scripts might throw us off
222
- return self .original_executable
197
+ if not (self .real_prefix or (self .base_prefix is not None and self .base_prefix != self .prefix )):
198
+ return self .original_executable
199
+
200
+ # if this is NOT a virtual environment, can't determine easily, bail out
201
+ if self .real_prefix is not None :
202
+ return None
203
+
204
+ base_executable = getattr (sys , "_base_executable" , None ) # some platforms may set this to help us
205
+ if base_executable is None : # use the saved system executable if present
206
+ return None
207
+
208
+ # we know we're in a virtual environment, can not be us
209
+ if sys .executable == base_executable :
210
+ return None
211
+
212
+ # We're not in a venv and base_executable exists; use it directly
213
+ if os .path .exists (base_executable ):
214
+ return base_executable
215
+
216
+ # Try fallback for POSIX virtual environments
217
+ return self ._try_posix_fallback_executable (base_executable )
218
+
219
+ def _try_posix_fallback_executable (self , base_executable ):
220
+ """
221
+ Try to find a versioned Python binary as fallback for POSIX virtual environments.
222
+
223
+ Python may return "python" because it was invoked from the POSIX virtual environment
224
+ however some installs/distributions do not provide a version-less "python" binary in
225
+ the system install location (see PEP 394) so try to fallback to a versioned binary.
226
+
227
+ Gate this to Python 3.11 as `sys._base_executable` path resolution is now relative to
228
+ the 'home' key from pyvenv.cfg which often points to the system install location.
229
+ """
230
+ major , minor = self .version_info .major , self .version_info .minor
231
+ if self .os != "posix" or (major , minor ) < (3 , 11 ):
232
+ return None
233
+
234
+ # search relative to the directory of sys._base_executable
235
+ base_dir = os .path .dirname (base_executable )
236
+ candidates = [f"python{ major } " , f"python{ major } .{ minor } " ]
237
+ if self .implementation == "PyPy" :
238
+ candidates .extend (["pypy" , "pypy3" , f"pypy{ major } " , f"pypy{ major } .{ minor } " ])
239
+
240
+ for candidate in candidates :
241
+ full_path = os .path .join (base_dir , candidate )
242
+ if os .path .exists (full_path ):
243
+ return full_path
244
+
245
+ return None # in this case we just can't tell easily without poking around FS and calling them, bail
223
246
224
247
def install_path (self , key ):
225
248
result = self .distutils_install .get (key )
0 commit comments