Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix find_python_executable error #331

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 26 additions & 12 deletions flit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import shutil
import subprocess
import sys
from typing import Optional

from flit_core import common
from .inifile import ConfigError
Expand All @@ -16,25 +17,37 @@
log = logging.getLogger(__name__)


class PythonNotFoundError(Exception): pass
class PythonNotFoundError(FileNotFoundError): pass

def find_python_executable(python):

def find_python_executable(python: Optional[str] = None) -> str:
Edward-Knight marked this conversation as resolved.
Show resolved Hide resolved
"""Returns an absolute filepath to the executable of Python to use."""
if not python:
python = os.environ.get("FLIT_INSTALL_PYTHON")
if not python:
return sys.executable
if os.path.isabs(python): # sys.executable is absolute too
return python
python = shutil.which(python)
Edward-Knight marked this conversation as resolved.
Show resolved Hide resolved
if not python:
raise PythonNotFoundError('Python executable {!r} not found'.format(python))
return subprocess.check_output(
[python, "-c", "import sys; print(sys.executable)"],
universal_newlines=True,
).strip()


def add_shared_install_options(parser):
# get absolute filepath of {python}
# shutil.which may give a different result to the raw subprocess call
# see https://github.com/takluyver/flit/pull/300 and https://bugs.python.org/issue38905
resolved_python = shutil.which(python)
if resolved_python is None:
raise PythonNotFoundError("Unable to resolve Python executable {!r}".format(python))
try:
return subprocess.check_output(
[resolved_python, "-c", "import sys; print(sys.executable)"],
universal_newlines=True,
).strip()
except Exception as e:
raise PythonNotFoundError(
"{} occurred trying to find the absolute filepath of Python executable {!r} ({!r})".format(
e.__class__.__name__, python, resolved_python
)
) from e


def add_shared_install_options(parser: argparse.ArgumentParser):
parser.add_argument('--user', action='store_true', default=None,
help="Do a user-local install (default if site.ENABLE_USER_SITE is True)"
)
Expand All @@ -45,6 +58,7 @@ def add_shared_install_options(parser):
help="Target Python executable, if different from the one running flit"
)


def main(argv=None):
ap = argparse.ArgumentParser()
ap.add_argument('-f', '--ini-file', type=pathlib.Path, default='pyproject.toml')
Expand Down
12 changes: 11 additions & 1 deletion tests/test_find_python_executable.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import os
import re
import sys

from flit import find_python_executable
import pytest

from flit import PythonNotFoundError, find_python_executable


def test_default():
Expand All @@ -18,3 +21,10 @@ def test_abs():

def test_find_in_path():
assert os.path.isabs(find_python_executable("python"))


@pytest.mark.parametrize("bad_python_name", ["pyhton", "ls", "."])
def test_exception(bad_python_name: str):
"""Test that an appropriate exception (that contains the error string) is raised."""
with pytest.raises(PythonNotFoundError, match=re.escape(bad_python_name)):
find_python_executable(bad_python_name)