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

Drop wheel and setuptools from shared libs #1078

Merged
merged 7 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## dev

- Drop `setuptools` and `wheel` from the shared libraries
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be a good idea to describe briefly what this means to end users.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, done. Have you already considered adopting towncrier for pipx? This would also simplify categorizing the changes.

- Allow running `pip` with `pipx run`
- Make usage message in `pipx run` show `package_or_url`, so extra will be printed out as well
- Add `--force-reinstall` to pip arguments when `--force` was passed
- Use the py launcher, if available, to select Python version with the `--python` option
Expand Down
8 changes: 4 additions & 4 deletions docs/how-pipx-works.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
When installing a package and its binaries on linux (`pipx install package`) pipx will

- create directory `~/.local/share/pipx/venvs/PACKAGE`
- create or re-use a shared virtual environment that contains shared packaging libraries `pip`, `setuptools` and `wheel` in `~/.local/share/pipx/shared/`
- ensure all packaging libraries are updated to their latest versions
- create or re-use a shared virtual environment that contains shared packaging library `pip` in `~/.local/share/pipx/shared/`
- ensure the library is updated to its latest version
- create a Virtual Environment in `~/.local/share/pipx/venvs/PACKAGE` that uses the shared pip mentioned above but otherwise is isolated (pipx uses a [.pth file]( https://docs.python.org/3/library/site.html) to do this)
- install the desired package in the Virtual Environment
- expose binaries at `~/.local/bin` that point to new binaries in `~/.local/share/pipx/venvs/PACKAGE/bin` (such as `~/.local/bin/black` -> `~/.local/share/pipx/venvs/black/bin/black`)
- As long as `~/.local/bin/` is on your PATH, you can now invoke the new binaries globally

When running a binary (`pipx run BINARY`), pipx will

- create or re-use a shared virtual environment that contains shared packaging libraries `pip`, `setuptools` and `wheel` in `~/.local/share/pipx/shared/`
- ensure all packaging libraries are updated to their latest versions
- create or re-use a shared virtual environment that contains the shared packaging library `pip`
- ensure the library is updated to its latest version
- create a temporary directory (or reuse a cached virtual environment for this package) with a name based on a hash of the attributes that make the run reproducible. This includes things like the package name, spec, python version, and pip arguments.
- create a Virtual Environment inside it with `python -m venv`
- install the desired package in the Virtual Environment
Expand Down
7 changes: 6 additions & 1 deletion src/pipx/commands/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,12 @@ def install(
return EXIT_CODE_INSTALL_VENV_EXISTS

try:
venv.create_venv(venv_args, pip_args)
# Enable installing shared library `pip` with `pipx`
override_shared = False

if package_name == "pip":
override_shared = True
chrysle marked this conversation as resolved.
Show resolved Hide resolved
venv.create_venv(venv_args, pip_args, override_shared)
for dep in preinstall_packages or []:
dep_name = package_name_from_spec(
dep, python, pip_args=pip_args, verbose=verbose
Expand Down
7 changes: 6 additions & 1 deletion src/pipx/commands/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,6 @@ def _download_and_run(
verbose: bool,
) -> NoReturn:
venv = Venv(venv_dir, python=python, verbose=verbose)
venv.create_venv(venv_args, pip_args)

if venv.pipx_metadata.main_package.package is not None:
package_name = venv.pipx_metadata.main_package.package
Expand All @@ -227,6 +226,12 @@ def _download_and_run(
package_or_url, python, pip_args=pip_args, verbose=verbose
)

override_shared = False

if package_name == "pip":
override_shared = True
chrysle marked this conversation as resolved.
Show resolved Hide resolved

venv.create_venv(venv_args, pip_args, override_shared)
venv.install_package(
package_name=package_name,
package_or_url=package_or_url,
Expand Down
6 changes: 2 additions & 4 deletions src/pipx/shared_libs.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ def __init__(self) -> None:
self.root = constants.PIPX_SHARED_LIBS
self.bin_path, self.python_path = get_venv_paths(self.root)
self.pip_path = self.bin_path / ("pip" if not WINDOWS else "pip.exe")
# i.e. bin_path is ~/.local/pipx/shared/bin
# i.e. python_path is ~/.local/pipx/shared/python
# i.e. bin_path is ~/.local/share/pipx/shared/bin
# i.e. python_path is ~/.local/share/pipx/shared/python
self._site_packages: Optional[Path] = None
self.has_been_updated_this_run = False
self.has_been_logged_this_run = False
Expand Down Expand Up @@ -107,8 +107,6 @@ def upgrade(
*_pip_args,
"--upgrade",
"pip",
chrysle marked this conversation as resolved.
Show resolved Hide resolved
"setuptools",
"wheel",
]
)
subprocess_post_check(upgrade_process)
Expand Down
34 changes: 21 additions & 13 deletions src/pipx/venv.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,24 +156,32 @@ def main_package_name(self) -> str:
else:
return self.pipx_metadata.main_package.package

def create_venv(self, venv_args: List[str], pip_args: List[str]) -> None:
def create_venv(
self, venv_args: List[str], pip_args: List[str], override_shared: bool = False
) -> None:
"""
override_shared -- Override installing shared libraries to the pipx shared directory (default False)
"""
with animate("creating virtual environment", self.do_animation):
cmd = [self.python, "-m", "venv", "--without-pip"]
cmd = [self.python, "-m", "venv"]
if not override_shared:
cmd.append("--without-pip")
venv_process = run_subprocess(cmd + venv_args + [str(self.root)])
subprocess_post_check(venv_process)

shared_libs.create(self.verbose)
pipx_pth = get_site_packages(self.python_path) / PIPX_SHARED_PTH
# write path pointing to the shared libs site-packages directory
# example pipx_pth location:
# ~/.local/pipx/venvs/black/lib/python3.8/site-packages/pipx_shared.pth
# example shared_libs.site_packages location:
# ~/.local/pipx/shared/lib/python3.6/site-packages
#
# https://docs.python.org/3/library/site.html
# A path configuration file is a file whose name has the form 'name.pth'.
# its contents are additional items (one per line) to be added to sys.path
pipx_pth.write_text(f"{shared_libs.site_packages}\n", encoding="utf-8")
if not override_shared:
pipx_pth = get_site_packages(self.python_path) / PIPX_SHARED_PTH
# write path pointing to the shared libs site-packages directory
# example pipx_pth location:
# ~/.local/share/pipx/venvs/black/lib/python3.8/site-packages/pipx_shared.pth
# example shared_libs.site_packages location:
# ~/.local/share/pipx/shared/lib/python3.6/site-packages
#
# https://docs.python.org/3/library/site.html
# A path configuration file is a file whose name has the form 'name.pth'.
# its contents are additional items (one per line) to be added to sys.path
pipx_pth.write_text(f"{shared_libs.site_packages}\n", encoding="utf-8")

self.pipx_metadata.venv_args = venv_args
self.pipx_metadata.python_version = self.get_python_version()
Expand Down
7 changes: 7 additions & 0 deletions tests/test_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,3 +334,10 @@ def test_run_with_windows_python_version(caplog, pipx_temp_env, tmp_path):
)
run_pipx_cli_exit(["run", script.as_uri(), "--python", "3.11"])
assert "3.11" in out.read_text()


@mock.patch("os.execvpe", new=execvpe_mock)
def test_run_shared_lib_as_app(pipx_temp_env, monkeypatch, capfd):
run_pipx_cli_exit(["run", "pip", "--help"])
captured = capfd.readouterr()
assert "pip <command> [options]\n" in captured.out
Loading