python-discovery 1.5.2__py3-none-any.whl → 1.5.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -198,25 +198,30 @@ class PythonInfoCollector:
198
198
 
199
199
  def _fast_get_system_executable(self):
200
200
  """Try to get the system executable by just looking at properties."""
201
- # if we're not in a virtual environment, this is already a system python, so return the original executable
202
- # note we must choose the original and not the pure executable as shim scripts might throw us off
201
+ # Preserve the invoked path because shims may rely on it.
203
202
  if not (self.real_prefix or (self.base_prefix is not None and self.base_prefix != self.prefix)):
204
203
  return self._resolve_executable_symlink(self.original_executable)
205
204
 
206
- # if this is NOT a virtual environment, can't determine easily, bail out
207
205
  if self.real_prefix is not None:
208
206
  return None
209
207
 
210
- base_executable = getattr(sys, "_base_executable", None) # some platforms may set this to help us
211
- if base_executable is None: # use the saved system executable if present
208
+ base_executable = getattr(sys, "_base_executable", None)
209
+ if base_executable is None:
212
210
  return None
213
211
 
214
- # we know we're in a virtual environment, can not be us
215
212
  if sys.executable == base_executable:
216
213
  return None
217
214
 
218
- # We're not in a venv and base_executable exists; use it directly
215
+ # CPython accepts pythonX without checking its version when resolving a copied venv.
219
216
  if os.path.exists(base_executable): # pragma: >=3.11 cover
217
+ major = self.version_info.major
218
+ ambiguous_names = {"python", "python{}".format(major)}
219
+ if self.implementation == "PyPy":
220
+ ambiguous_names.update({"pypy", "pypy3", "pypy{}".format(major)})
221
+ if os.path.basename(base_executable) in ambiguous_names:
222
+ versioned = self._try_posix_versioned_executable(base_executable)
223
+ if versioned is not None and not os.path.samefile(base_executable, versioned):
224
+ base_executable = versioned
220
225
  return self._resolve_executable_symlink(base_executable)
221
226
 
222
227
  # Try fallback for POSIX virtual environments
@@ -259,28 +264,48 @@ class PythonInfoCollector:
259
264
 
260
265
  def _try_posix_fallback_executable(self, base_executable):
261
266
  """Find a versioned Python binary as fallback for POSIX virtual environments."""
267
+ versioned = self._try_posix_versioned_executable(base_executable)
268
+ if versioned is not None:
269
+ return versioned
270
+
271
+ major, minor = self.version_info.major, self.version_info.minor
272
+ if self.os != "posix" or (major, minor) < (3, 11):
273
+ return None
274
+
275
+ base_dir = os.path.dirname(base_executable)
276
+ candidates = ["python{}".format(major)]
277
+ if self.implementation == "PyPy":
278
+ candidates.extend(["pypy", "pypy3", "pypy{}".format(major)])
279
+
280
+ for candidate in candidates:
281
+ full_path = os.path.join(base_dir, candidate)
282
+ if os.path.exists(full_path):
283
+ return full_path
284
+
285
+ return None
286
+
287
+ def _try_posix_versioned_executable(self, base_executable):
262
288
  major, minor = self.version_info.major, self.version_info.minor
263
289
  if self.os != "posix" or (major, minor) < (3, 11):
264
290
  return None
265
291
 
266
- # search relative to the directory of sys._base_executable
267
292
  base_dir = os.path.dirname(base_executable)
268
- candidates = ["python{}".format(major), "python{}.{}".format(major, minor)]
293
+ candidates = ["python{}.{}".format(major, minor)]
269
294
  if self.implementation == "PyPy":
270
- candidates.extend(["pypy", "pypy3", "pypy{}".format(major), "pypy{}.{}".format(major, minor)])
295
+ candidates.insert(0, "pypy{}.{}".format(major, minor))
271
296
 
272
297
  for candidate in candidates:
273
298
  full_path = os.path.join(base_dir, candidate)
274
299
  if os.path.exists(full_path):
275
300
  return full_path
276
301
 
277
- return None # in this case we just can't tell easily without poking around FS and calling them, bail
302
+ return None
278
303
 
279
304
  @staticmethod
280
305
  def _distutils_install(): # pragma: <3.11 cover # 3.11+ uses the "venv" scheme instead
281
306
  # use distutils primarily because that's what pip does
282
307
  # https://github.com/pypa/pip/blob/main/src/pip/_internal/locations.py#L95
283
- # note here we don't import Distribution directly to allow setuptools to patch it
308
+ # Avoid importing Distribution before setuptools can patch it.
284
309
  with warnings.catch_warnings(): # disable warning for PEP-632
285
310
  warnings.simplefilter("ignore")
286
311
  try:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: python-discovery
3
- Version: 1.5.2
3
+ Version: 1.5.3
4
4
  Summary: Python interpreter discovery
5
5
  Project-URL: Changelog, https://github.com/tox-dev/python-discovery/releases
6
6
  Project-URL: Documentation, https://python-discovery.readthedocs.io
@@ -4,14 +4,14 @@ python_discovery/_cached_py_info.py,sha256=MKV2sjrrypq-7gcOdw9GpAooMJl9kYCTAlYeU
4
4
  python_discovery/_compat.py,sha256=iqxGuhK9rPaiui80G1H1KrweoMJ16gyLYEmUrSXrp5c,709
5
5
  python_discovery/_discovery.py,sha256=ABPD8MRweUO6B7cG3U3ZBfUIYs08rh6dYPA225EURyY,22032
6
6
  python_discovery/_py_info.py,sha256=XX4yM6TVhTMFfmahNMekT7Y3Zy12Zy0IAfmz_xFRceU,25284
7
- python_discovery/_py_info_collect.py,sha256=NSh00CS1UHI6_fbXrXUi-vlvFAEOix2NnC7Is10Taeg,15439
7
+ python_discovery/_py_info_collect.py,sha256=YhF5U-kKcwMXZMfRNDlZK6kCPJJI9tHIvd5SjQqMJqY,16126
8
8
  python_discovery/_py_spec.py,sha256=O1RMC9JQ7m5SRzF6cEELxnIWZpadXYWO4bWDD7TemUs,10965
9
9
  python_discovery/_specifier.py,sha256=o7MHb0z_mFSLz9gXqMwJoNkHYjgi2biq3Ibvd0_slvc,10457
10
10
  python_discovery/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  python_discovery/_windows/__init__.py,sha256=qthcyGh36b3WkeSbZ4ECRRYLbCOCaQu5X_DRZ98tXfk,315
12
12
  python_discovery/_windows/_pep514.py,sha256=1TqLTdofSCPu3VFE7D4u2fXweyaqhKJR7b48VmJ9AQQ,7787
13
13
  python_discovery/_windows/_propose.py,sha256=iMJf6l0TU4SvuV8UsCHHINAe9L5dUT949xyeyMVdong,1565
14
- python_discovery-1.5.2.dist-info/METADATA,sha256=4kPFZVceJ_w4hP8AKPig_59eT502_O4NEzjeTyjMECw,5132
15
- python_discovery-1.5.2.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
16
- python_discovery-1.5.2.dist-info/licenses/LICENSE,sha256=kOJeH68qSq6o2V7o5_VziwUqGswMnFgGgQH5Mahr1Yg,1023
17
- python_discovery-1.5.2.dist-info/RECORD,,
14
+ python_discovery-1.5.3.dist-info/METADATA,sha256=RcMFPQt1KzopnhBQlUIjMC18xeM-te8dXAsUwKI6D2Y,5132
15
+ python_discovery-1.5.3.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
16
+ python_discovery-1.5.3.dist-info/licenses/LICENSE,sha256=kOJeH68qSq6o2V7o5_VziwUqGswMnFgGgQH5Mahr1Yg,1023
17
+ python_discovery-1.5.3.dist-info/RECORD,,