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

add the --pip-use-shebang-python option #222

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions docs/cli-reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,7 @@ Also note that you can always fix the shebang during installation of a zipapp us
.. code-block:: shell

python3 -m zipapp -p '/usr/bin/env python3.7' -o ~/bin/foo foo.pyz

If the interpreter you run is different from the interpreter of the sheband line,
you can use the :option:`--pip-use-shebang-python` to use the shebang interpreter when installing packages through pip
(important for version specific packages).
35 changes: 33 additions & 2 deletions src/shiv/cli.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import hashlib
import os
import shutil
import subprocess
import sys
import time

Expand Down Expand Up @@ -156,6 +157,11 @@ def copytree(src: Path, dst: Path) -> None:
),
)
@click.option("--root", type=click.Path(), help="Override the 'root' path (default is ~/.shiv).")
@click.option(
"--pip-use-shebang-python",
is_flag=True,
help="Use the python interpreter from the shebang line when installing the pip packages.",
)
@click.argument("pip_args", nargs=-1, type=click.UNPROCESSED)
def main(
output_file: str,
Expand All @@ -172,6 +178,7 @@ def main(
preamble: Optional[str],
root: Optional[str],
pip_args: List[str],
pip_use_shebang_python: bool,
) -> None:
"""
Shiv is a command line utility for building fully self-contained Python zipapps
Expand All @@ -181,6 +188,14 @@ def main(
if not pip_args and not site_packages:
sys.exit(NO_PIP_ARGS_OR_SITE_PACKAGES)

if python:
python = str(python)
else:
if os.name == "nt":
python = sys.executable
else:
python = DEFAULT_SHEBANG

if output_file is None:
sys.exit(NO_OUTFILE)

Expand Down Expand Up @@ -212,7 +227,23 @@ def main(

if pip_args:
# Install dependencies into staged site-packages.
pip.install(["--target", tmp_site_packages] + list(pip_args))
if pip_use_shebang_python:
assert python is not None, "You should have specified a python interpreter."
pip_interpreter = python
else:
version_sys = subprocess.run([sys.executable, "-V"], capture_output=True).stdout.decode().rstrip()
version_shebang = subprocess.run([python, "-V"], capture_output=True).stdout.decode().rstrip()
if version_sys != version_shebang:
click.secho(
f"You are installing pip packages with your current python interpreter ({version_sys}) "
f"while the python interpreter used in your shebang line is ({version_shebang}). "
f"If you want to use the python interpreter from your shebang line to install the "
f"pip packages, you must activate the option 'pip_use_shebang_python'.",
err=True,
fg="red",
)
pip_interpreter = sys.executable
pip.install(["--target", tmp_site_packages] + list(pip_args), pip_interpreter=pip_interpreter)

if preamble:
bin_dir = Path(tmp_site_packages, "bin")
Expand Down Expand Up @@ -269,7 +300,7 @@ def main(
builder.create_archive(
sources,
target=Path(output_file).expanduser(),
interpreter=python or DEFAULT_SHEBANG,
interpreter=python,
main="_bootstrap:bootstrap",
env=env,
compressed=compressed,
Expand Down
6 changes: 3 additions & 3 deletions src/shiv/pip.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ def clean_pip_env() -> Generator[None, None, None]:
os.environ[PIP_REQUIRE_VIRTUALENV] = require_venv


def install(args: List[str]) -> None:
def install(args: List[str], pip_interpreter: str) -> None:
"""`pip install` as a function.

Accepts a list of pip arguments.
Accepts a list of pip arguments and the python interpreter to use when running pip.

.. code-block:: py

Expand All @@ -54,7 +54,7 @@ def install(args: List[str]) -> None:
extend_python_path(subprocess_env, sys.path[sitedir_index:])

process = subprocess.Popen(
[sys.executable, "-m", "pip", "--disable-pip-version-check", "install", *args],
[pip_interpreter, "-m", "pip", "--disable-pip-version-check", "install", *args],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
env=subprocess_env,
Expand Down