Esempio n. 1
0
def do_use(project: Project, python: str) -> None:
    """Use the specified python version and save in project config.
    The python can be a version string or interpreter path.
    """
    if Path(python).is_absolute():
        python_path = python
    else:
        python_path = shutil.which(python)
        if not python_path:
            finder = pythonfinder.Finder()
            try:
                python_path = finder.find_python_version(
                    python).path.as_posix()
            except AttributeError:
                raise NoPythonVersion(
                    f"Python {python} is not found on the system.")

    python_version = get_python_version(python_path, True)
    if not project.python_requires.contains(python_version):
        raise NoPythonVersion("The target Python version {} doesn't satisfy "
                              "the Python requirement: {}".format(
                                  python_version, project.python_requires))
    context.io.echo("Using Python interpreter: {} ({})".format(
        context.io.green(python_path), python_version))

    project.config["python"] = Path(python_path).as_posix()
    project.config.save_config()
Esempio n. 2
0
def do_use(project: Project, python: str, first: bool = False) -> None:
    """Use the specified python version and save in project config.
    The python can be a version string or interpreter path.
    """
    import pythonfinder

    python = python.strip()
    if python and not all(c.isdigit() for c in python.split(".")):
        if Path(python).exists():
            python_path = find_python_in_path(python)
        else:
            python_path = shutil.which(python)
        if not python_path:
            raise NoPythonVersion(f"{python} is not a valid Python.")
        python_version, is_64bit = get_python_version(python_path, True)
    else:
        finder = pythonfinder.Finder()
        pythons = []
        args = [int(v) for v in python.split(".") if v != ""]
        for i, entry in enumerate(finder.find_all_python_versions(*args)):
            python_version, is_64bit = get_python_version(entry.path.as_posix(), True)
            pythons.append((entry.path.as_posix(), python_version, is_64bit))
        if not pythons:
            raise NoPythonVersion(f"Python {python} is not available on the system.")

        if not first and len(pythons) > 1:
            for i, (path, python_version, is_64bit) in enumerate(pythons):
                stream.echo(
                    f"{i}. {stream.green(path)} "
                    f"({get_python_version_string(python_version, is_64bit)})"
                )
            selection = click.prompt(
                "Please select:",
                type=click.Choice([str(i) for i in range(len(pythons))]),
                default="0",
                show_choices=False,
            )
        else:
            selection = 0
        python_path, python_version, is_64bit = pythons[int(selection)]

    if not project.python_requires.contains(python_version):
        raise NoPythonVersion(
            "The target Python version {} doesn't satisfy "
            "the Python requirement: {}".format(python_version, project.python_requires)
        )
    stream.echo(
        "Using Python interpreter: {} ({})".format(
            stream.green(python_path),
            get_python_version_string(python_version, is_64bit),
        )
    )
    old_path = project.config.get("python.path")
    new_path = python_path
    project.project_config["python.path"] = Path(new_path).as_posix()
    if old_path and Path(old_path) != Path(new_path) and not project.is_global:
        stream.echo(stream.cyan("Updating executable scripts..."))
        project.environment.update_shebangs(new_path)
Esempio n. 3
0
    def resolve_interpreter(self) -> PythonInfo:
        """Get the Python interpreter path."""
        config = self.config
        if self.project_config.get(
                "python.path") and not os.getenv("PDM_IGNORE_SAVED_PYTHON"):
            saved_path = self.project_config["python.path"]
            try:
                return PythonInfo.from_path(saved_path)
            except (ValueError, FileNotFoundError):
                del self.project_config["python.path"]
        if os.name == "nt":
            suffix = ".exe"
            scripts = "Scripts"
        else:
            suffix = ""
            scripts = "bin"
        virtual_env = os.getenv("VIRTUAL_ENV")
        if config["use_venv"] and virtual_env:
            return PythonInfo.from_path(
                os.path.join(virtual_env, scripts, f"python{suffix}"))

        for py_version in self.find_interpreters():
            if self.python_requires.contains(str(py_version.version)):
                self.python = py_version
                return py_version

        raise NoPythonVersion(
            "No Python that satisfies {} is found on the system.".format(
                self.python_requires))
Esempio n. 4
0
File: core.py Progetto: linw1995/pdm
    def resolve_interpreter(self) -> str:
        """Get the Python interpreter path."""
        config = self.config
        if self.project_config.get(
                "python.path") and not os.getenv("PDM_IGNORE_SAVED_PYTHON"):
            saved_path = self.project_config["python.path"]
            if not os.path.isfile(saved_path):
                del self.project_config["python.path"]
            else:
                return saved_path
        if os.name == "nt":
            suffix = ".exe"
            scripts = "Scripts"
        else:
            suffix = ""
            scripts = "bin"
        virtual_env = os.getenv("VIRTUAL_ENV")
        if config["use_venv"] and virtual_env:
            return os.path.join(virtual_env, scripts, f"python{suffix}")

        for py_version in self.find_interpreters():
            if self.python_requires.contains(str(py_version.version)):
                self.python_executable = py_version.executable
                return self.python_executable

        raise NoPythonVersion(
            "No Python that satisfies {} is found on the system.".format(
                self.python_requires))
Esempio n. 5
0
def do_use(project: Project, python: str, first: bool = False) -> None:
    """Use the specified python version and save in project config.
    The python can be a version string or interpreter path.
    """
    if not all(c.isdigit() for c in python.split(".")):
        if Path(python).exists():
            python_path = Path(python).absolute().as_posix()
        else:
            python_path = shutil.which(python)
        if not python_path:
            raise NoPythonVersion(f"{python} is not a valid Python.")
        python_version = get_python_version(python_path, True)
    else:
        finder = pythonfinder.Finder()
        pythons = []
        args = [int(v) for v in python.split(".")]
        for i, entry in enumerate(finder.find_all_python_versions(*args)):
            python_version = get_python_version(entry.path.as_posix(), True)
            pythons.append((entry.path.as_posix(), python_version))
        if not pythons:
            raise NoPythonVersion(
                f"Python {python} is not available on the system.")

        if not first and len(pythons) > 1:
            for i, (path, python_version) in enumerate(pythons):
                context.io.echo(
                    f"{i}: {context.io.green(path)} ({python_version})")
            selection = click.prompt(
                "Please select:",
                type=click.Choice([str(i) for i in range(len(pythons))]),
                default="0",
                show_choices=False,
            )
        else:
            selection = 0
        python_path, python_version = pythons[int(selection)]

    if not project.python_requires.contains(python_version):
        raise NoPythonVersion("The target Python version {} doesn't satisfy "
                              "the Python requirement: {}".format(
                                  python_version, project.python_requires))
    context.io.echo("Using Python interpreter: {} ({})".format(
        context.io.green(python_path), python_version))

    project.config["python.path"] = Path(python_path).as_posix()
    project.config.save_config()
Esempio n. 6
0
    def python_executable(self) -> str:
        """Get the Python interpreter path."""
        config = self.config
        if self.project_config.get(
                "python.path") and not os.getenv("PDM_IGNORE_SAVED_PYTHON"):
            return self.project_config["python.path"]
        path = None
        if config["use_venv"]:
            path = get_venv_python(self.root)
            if path:
                stream.echo(
                    f"Virtualenv interpreter {stream.green(path)} is detected.",
                    err=True,
                    verbosity=stream.DETAIL,
                )
        if not path and PYENV_INSTALLED and config.get("python.use_pyenv",
                                                       True):
            path = Path(PYENV_ROOT, "shims", "python").as_posix()
        if not path:
            path = shutil.which("python")

        version = None
        if path:
            try:
                version, _ = get_python_version(path, True)
            except (FileNotFoundError, subprocess.CalledProcessError):
                version = None
        if not version or not self.python_requires.contains(version):
            finder = Finder()
            for python in finder.find_all_python_versions():
                version, _ = get_python_version(python.path.as_posix(), True)
                if self.python_requires.contains(version):
                    path = python.path.as_posix()
                    break
            else:
                version = ".".join(map(str, sys.version_info[:3]))
                if self.python_requires.contains(version):
                    path = sys.executable
        if path:
            if os.path.normcase(path) == os.path.normcase(sys.executable):
                # Refer to the base interpreter to allow for venvs
                path = getattr(sys, "_base_executable", sys.executable)
            stream.echo(
                "Using Python interpreter: {} ({})".format(
                    stream.green(path), version),
                err=True,
            )
            if not os.getenv("PDM_IGNORE_SAVED_PYTHON"):
                self.project_config["python.path"] = Path(path).as_posix()
            return path
        raise NoPythonVersion(
            "No Python that satisfies {} is found on the system.".format(
                self.python_requires))
Esempio n. 7
0
File: actions.py Progetto: ulwlu/pdm
def do_use(project: Project,
           python: Optional[str] = "",
           first: Optional[bool] = False) -> None:
    """Use the specified python version and save in project config.
    The python can be a version string or interpreter path.
    """
    def version_matcher(py_version):
        return project.python_requires.contains(str(py_version.version))

    python = python.strip()

    found_interpreters = list(
        dict.fromkeys(
            filter(version_matcher, project.find_interpreters(python))))
    if not found_interpreters:
        raise NoPythonVersion("Python interpreter is not found on the system.")
    if first or len(found_interpreters) == 1:
        selected_python = found_interpreters[0]
    else:
        project.core.ui.echo("Please enter the Python interpreter to use")
        for i, py_version in enumerate(found_interpreters):
            python_version = str(py_version.version)
            is_64bit = py_version.get_architecture() == "64bit"
            version_string = get_python_version_string(python_version,
                                                       is_64bit)
            project.core.ui.echo(
                f"{i}. {termui.green(py_version.executable)} ({version_string})"
            )
        selection = click.prompt(
            "Please select:",
            type=click.Choice([str(i)
                               for i in range(len(found_interpreters))]),
            default="0",
            show_choices=False,
        )
        selected_python = found_interpreters[int(selection)]

    old_path = project.config.get("python.path")
    new_path = selected_python.executable
    python_version = str(selected_python.version)
    is_64bit = selected_python.get_architecture() == "64bit"
    project.core.ui.echo("Using Python interpreter: {} ({})".format(
        termui.green(str(new_path)),
        get_python_version_string(python_version, is_64bit),
    ))
    project.python_executable = new_path
    if old_path and Path(old_path) != Path(new_path) and not project.is_global:
        project.core.ui.echo(termui.cyan("Updating executable scripts..."))
        project.environment.update_shebangs(new_path)
Esempio n. 8
0
def do_use(project: Project, python: str = "", first: bool = False) -> None:
    """Use the specified python version and save in project config.
    The python can be a version string or interpreter path.
    """
    def version_matcher(py_version: PythonInfo) -> bool:
        return project.python_requires.contains(str(py_version.version))

    if python:
        python = python.strip()

    found_interpreters = list(
        dict.fromkeys(
            filter(version_matcher, project.find_interpreters(python))))
    if not found_interpreters:
        raise NoPythonVersion("Python interpreter is not found on the system.")
    if first or len(found_interpreters) == 1:
        selected_python = found_interpreters[0]
    else:
        project.core.ui.echo("Please enter the Python interpreter to use")
        for i, py_version in enumerate(found_interpreters):
            project.core.ui.echo(
                f"{i}. {termui.green(py_version.executable)} ({py_version.identifier})"
            )
        selection = click.prompt(
            "Please select:",
            type=click.Choice([str(i)
                               for i in range(len(found_interpreters))]),
            default="0",
            show_choices=False,
        )
        selected_python = found_interpreters[int(selection)]

    old_path = project.python.executable if "python.path" in project.config else None
    new_path = selected_python.executable
    project.core.ui.echo("Using Python interpreter: {} ({})".format(
        termui.green(str(new_path)),
        selected_python.identifier,
    ))
    project.python = selected_python
    if (old_path and Path(old_path) != Path(new_path)
            and not project.environment.is_global):
        project.core.ui.echo(termui.cyan("Updating executable scripts..."))
        project.environment.update_shebangs(old_path, new_path)
Esempio n. 9
0
    def python_executable(self) -> str:
        """Get the Python interpreter path."""
        config = self.project.config
        if config.get("python.path"):
            return config["python.path"]
        if PYENV_INSTALLED and config.get("python.use_pyenv", True):
            return os.path.join(PYENV_ROOT, "shims", "python")
        if "VIRTUAL_ENV" in os.environ:
            stream.echo(
                "An activated virtualenv is detected, reuse the interpreter now.",
                err=True,
                verbosity=stream.DETAIL,
            )
            return get_venv_python(self.project.root)

        # First try what `python` refers to.
        path = shutil.which("python")
        version = None
        if path:
            version, _ = get_python_version(path, True)
        if not version or not self.python_requires.contains(version):
            finder = Finder()
            for python in finder.find_all_python_versions():
                version, _ = get_python_version(python.path.as_posix(), True)
                if self.python_requires.contains(version):
                    path = python.path.as_posix()
                    break
            else:
                version = ".".join(map(str, sys.version_info[:3]))
                if self.python_requires.contains(version):
                    path = sys.executable
        if path:
            stream.echo(
                "Using Python interpreter: {} ({})".format(stream.green(path), version)
            )
            self.project.project_config["python.path"] = Path(path).as_posix()
            return path
        raise NoPythonVersion(
            "No Python that satisfies {} is found on the system.".format(
                self.python_requires
            )
        )
Esempio n. 10
0
    def resolve_interpreter(self) -> PythonInfo:
        """Get the Python interpreter path."""
        config = self.config
        if config.get("python.path") and not os.getenv("PDM_IGNORE_SAVED_PYTHON"):
            saved_path = config["python.path"]
            python = PythonInfo.from_path(saved_path)
            if python.valid and self.python_requires.contains(
                str(python.version), True
            ):
                return python
            self.project_config.pop("python.path", None)
        if os.name == "nt":
            suffix = ".exe"
            scripts = "Scripts"
        else:
            suffix = ""
            scripts = "bin"

        # Resolve virtual environments from env-vars
        virtual_env = os.getenv("VIRTUAL_ENV", os.getenv("CONDA_PREFIX"))
        if config["python.use_venv"] and virtual_env:
            python = PythonInfo.from_path(
                os.path.join(virtual_env, scripts, f"python{suffix}")
            )
            if python.valid:
                return python

        for py_version in self.find_interpreters():
            if py_version.valid and self.python_requires.contains(
                str(py_version.version), True
            ):
                self.python = py_version
                return py_version

        raise NoPythonVersion(
            "No Python that satisfies {} is found on the system.".format(
                self.python_requires
            )
        )
Esempio n. 11
0
def find_python_in_path(path: os.PathLike) -> str:
    """Find a python interpreter from the given path, the input argument could be:

    - A valid path to the interpreter
    - A Python root diretory that contains the interpreter
    """
    pathlib_path = Path(path).absolute()
    if pathlib_path.is_file():
        return pathlib_path.as_posix()

    if os.name == "nt":
        for root_dir in (pathlib_path, pathlib_path / "Scripts"):
            if root_dir.joinpath("python.exe").exists():
                return root_dir.joinpath("python.exe").as_posix()
    else:
        executable_pattern = re.compile(r"python(?:\d(?:\.\d+m?)?)?$")

        for python in pathlib_path.joinpath("bin").glob("python*"):
            if executable_pattern.match(python.name):
                return python.as_posix()

    raise NoPythonVersion(f"No Python interpreter is found at {path!r}")
Esempio n. 12
0
    def python_executable(self) -> str:
        """Get the Python interpreter path."""
        path = None
        if self.config["python"]:
            path = self.config["python"]
            try:
                get_python_version(path)
                return path
            except Exception:
                pass

        path = None
        version = None
        # First try what `python` refers to.
        path = shutil.which("python")
        if path:
            version = get_python_version(path, True)
        else:
            finder = Finder()
            for python in finder.find_all_python_versions():
                version = ".".join(
                    map(str, get_python_version(python.path.as_posix())))
                if self.python_requires.contains(version):
                    path = python.path.as_posix()
                    break
            else:
                version = ".".join(map(str, sys.version_info[:3]))
                if self.python_requires.contains(version):
                    path = sys.executable
        if path:
            context.io.echo("Using Python interpreter: {} ({})".format(
                context.io.green(path), version))
            self.config["python"] = Path(path).as_posix()
            self.config.save_config()
            return path
        raise NoPythonVersion(
            "No Python that satisfies {} is found on the system.".format(
                self.python_requires))
Esempio n. 13
0
    def python_executable(self) -> str:
        """Get the Python interpreter path."""
        if self.config.get("python.path"):
            path = self.config["python.path"]
            try:
                get_python_version(path)
                return path
            except Exception:
                pass
        if PYENV_INSTALLED and self.config.get("python.use_pyenv", True):
            return os.path.join(PYENV_ROOT, "shims", "python")

        # First try what `python` refers to.
        path = shutil.which("python")
        version = None
        if path:
            version = get_python_version(path, True)
        if not version or not self.python_requires.contains(version):
            finder = Finder()
            for python in finder.find_all_python_versions():
                version = get_python_version(python.path.as_posix(), True)
                if self.python_requires.contains(version):
                    path = python.path.as_posix()
                    break
            else:
                version = ".".join(map(str, sys.version_info[:3]))
                if self.python_requires.contains(version):
                    path = sys.executable
        if path:
            context.io.echo("Using Python interpreter: {} ({})".format(
                context.io.green(path), version))
            self.config["python.path"] = Path(path).as_posix()
            self.config.save_config()
            return path
        raise NoPythonVersion(
            "No Python that satisfies {} is found on the system.".format(
                self.python_requires))
Esempio n. 14
0
def do_use(
    project: Project,
    python: str = "",
    first: bool = False,
    ignore_remembered: bool = False,
) -> None:
    """Use the specified python version and save in project config.
    The python can be a version string or interpreter path.
    """
    if python:
        python = python.strip()

    def version_matcher(py_version: PythonInfo) -> bool:
        return project.python_requires.contains(str(py_version.version), True)

    if not project.cache_dir.exists():
        project.cache_dir.mkdir(parents=True)
    use_cache: JSONFileCache[str, str] = JSONFileCache(
        project.cache_dir / "use_cache.json"
    )
    selected_python: PythonInfo | None = None
    if python and not ignore_remembered:
        if use_cache.has_key(python):
            path = use_cache.get(python)
            cached_python = PythonInfo.from_path(path)
            if not cached_python.valid:
                project.core.ui.echo(
                    f"The last selection is corrupted. {path!r}",
                    fg="red",
                    err=True,
                )
            elif version_matcher(cached_python):
                project.core.ui.echo(
                    "Using the last selection, add '-i' to ignore it.",
                    fg="yellow",
                    err=True,
                )
                selected_python = cached_python

    if selected_python is None:
        found_interpreters = list(dict.fromkeys(project.find_interpreters(python)))
        matching_interperters = list(filter(version_matcher, found_interpreters))
        if not found_interpreters:
            raise NoPythonVersion("Python interpreter is not found on the system.")
        if not matching_interperters:
            project.core.ui.echo("Interpreters found but not matching:", err=True)
            for py in found_interpreters:
                project.core.ui.echo(f"  - {py.executable} ({py.identifier})", err=True)
            raise NoPythonVersion(
                "No python is found meeting the requirement "
                f"{termui.green('python' + str(project.python_requires))}"
            )
        if first or len(matching_interperters) == 1:
            selected_python = matching_interperters[0]
        else:
            project.core.ui.echo("Please enter the Python interpreter to use")
            for i, py_version in enumerate(matching_interperters):
                project.core.ui.echo(
                    f"{i}. {termui.green(str(py_version.executable))} "
                    f"({py_version.identifier})"
                )
            selection = click.prompt(
                "Please select:",
                type=click.Choice([str(i) for i in range(len(matching_interperters))]),
                default="0",
                show_choices=False,
            )
            selected_python = matching_interperters[int(selection)]
        if python:
            use_cache.set(python, selected_python.path.as_posix())

    if not selected_python.valid:
        path = str(selected_python.executable)
        raise InvalidPyVersion(f"Invalid Python interpreter: {path}")

    old_python = project.python if "python.path" in project.config else None
    project.core.ui.echo(
        "Using Python interpreter: {} ({})".format(
            termui.green(str(selected_python.executable)),
            selected_python.identifier,
        )
    )
    project.python = selected_python
    if (
        old_python
        and old_python.path != selected_python.path
        and not project.environment.is_global
    ):
        project.core.ui.echo(termui.cyan("Updating executable scripts..."))
        project.environment.update_shebangs(selected_python.executable.as_posix())