builtin.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. """Virtualenv-specific Builtin discovery wrapping py_discovery."""
  2. from __future__ import annotations
  3. import sys
  4. from typing import TYPE_CHECKING
  5. from python_discovery import get_interpreter as _get_interpreter
  6. from .discover import Discover
  7. if TYPE_CHECKING:
  8. from argparse import ArgumentParser
  9. from collections.abc import Iterable, Mapping, Sequence
  10. from python_discovery import PyInfoCache, PythonInfo
  11. from virtualenv.config.cli.parser import VirtualEnvOptions
  12. def get_interpreter(
  13. key: str,
  14. try_first_with: Iterable[str],
  15. cache: PyInfoCache | None = None,
  16. env: Mapping[str, str] | None = None,
  17. app_data: PyInfoCache | None = None,
  18. ) -> PythonInfo | None:
  19. return _get_interpreter(key, try_first_with, cache or app_data, env)
  20. class Builtin(Discover):
  21. python_spec: Sequence[str]
  22. app_data: PyInfoCache
  23. try_first_with: Sequence[str]
  24. def __init__(self, options: VirtualEnvOptions) -> None:
  25. super().__init__(options)
  26. self.python_spec = options.python or [sys.executable]
  27. if self._env.get("VIRTUALENV_PYTHON"):
  28. self.python_spec = self.python_spec[1:] + self.python_spec[:1]
  29. self.app_data = options.app_data
  30. self.try_first_with = options.try_first_with
  31. @classmethod
  32. def add_parser_arguments(cls, parser: ArgumentParser) -> None:
  33. parser.add_argument(
  34. "-p",
  35. "--python",
  36. dest="python",
  37. metavar="py",
  38. type=str,
  39. action="append",
  40. default=[],
  41. help="interpreter based on what to create environment (path/identifier/version-specifier) "
  42. "- by default use the interpreter where the tool is installed - first found wins. "
  43. "Version specifiers (e.g., >=3.12, ~=3.11.0, ==3.10) are also supported",
  44. )
  45. parser.add_argument(
  46. "--try-first-with",
  47. dest="try_first_with",
  48. metavar="py_exe",
  49. type=str,
  50. action="append",
  51. default=[],
  52. help="try first these interpreters before starting the discovery",
  53. )
  54. def run(self) -> PythonInfo | None:
  55. for python_spec in self.python_spec:
  56. if result := get_interpreter(
  57. python_spec,
  58. self.try_first_with,
  59. app_data=self.app_data,
  60. env=self._env,
  61. ):
  62. return result
  63. return None
  64. def __repr__(self) -> str:
  65. spec = self.python_spec[0] if len(self.python_spec) == 1 else self.python_spec
  66. return f"{self.__class__.__name__} discover of python_spec={spec!r}"
  67. __all__ = [
  68. "Builtin",
  69. "get_interpreter",
  70. ]