_propose.py 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. from __future__ import annotations
  2. from typing import TYPE_CHECKING
  3. from python_discovery._py_info import PythonInfo
  4. from python_discovery._py_spec import PythonSpec
  5. from ._pep514 import discover_pythons
  6. if TYPE_CHECKING:
  7. from collections.abc import Generator, Mapping
  8. from python_discovery._cache import PyInfoCache
  9. _IMPLEMENTATION_BY_ORG: dict[str, str] = {
  10. "ContinuumAnalytics": "CPython",
  11. "PythonCore": "CPython",
  12. }
  13. class Pep514PythonInfo(PythonInfo):
  14. """A Python information acquired from PEP-514."""
  15. def propose_interpreters(
  16. spec: PythonSpec,
  17. cache: PyInfoCache | None,
  18. env: Mapping[str, str],
  19. ) -> Generator[PythonInfo, None, None]:
  20. existing = list(discover_pythons())
  21. existing.sort(
  22. key=lambda i: (
  23. *tuple(-1 if j is None else j for j in i[1:4]),
  24. 1 if i[0] == "PythonCore" else 0,
  25. ),
  26. reverse=True,
  27. )
  28. for name, major, minor, arch, threaded, exe, _ in existing:
  29. implementation = _IMPLEMENTATION_BY_ORG.get(name, name)
  30. skip_pre_filter = implementation.lower() != "cpython"
  31. registry_spec = PythonSpec("", implementation, major, minor, None, arch, exe, free_threaded=threaded)
  32. if skip_pre_filter or registry_spec.satisfies(spec):
  33. interpreter = Pep514PythonInfo.from_exe(exe, cache, env=env, raise_on_error=False)
  34. if interpreter is not None and interpreter.satisfies(spec, impl_must_match=True):
  35. yield interpreter
  36. __all__ = [
  37. "Pep514PythonInfo",
  38. "propose_interpreters",
  39. ]