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

Implementation of stored pipx metadata #222

Merged
merged 162 commits into from
Dec 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
162 commits
Select commit Hold shift + click to select a range
e94f258
Add pipxrc in each venv dir to hold pipxrc info
itsayellow Sep 19, 2019
0a54950
Add return value type to _read_pipxrc.
itsayellow Sep 20, 2019
88aed02
Rename _create_pipxrc -> _write_pipxrc, change arg.
itsayellow Sep 20, 2019
7876b86
New home for all pipxrc-related functions.
itsayellow Sep 20, 2019
eabb88f
Use pipxrc functions from pipxrc.py.
itsayellow Sep 20, 2019
7c283ef
Get cached venv metadata from pipxrc.
itsayellow Sep 20, 2019
7625e6b
Store new injected package in pipxrc.
itsayellow Sep 20, 2019
48b3e13
Fall back on venv.get_venv_metadata if no cached.
itsayellow Sep 20, 2019
8045dde
Rename JsonPathEncoder -> JsonEncoderPipx, ser changes.
itsayellow Sep 21, 2019
dbba307
Make pipxrc pretty-printed.
itsayellow Sep 21, 2019
7606834
Make reinstall-all re-inject injected packages.
itsayellow Sep 21, 2019
5f0854c
Add TODO comment.
itsayellow Sep 21, 2019
bc36f45
Fixed lint according to black.
itsayellow Sep 21, 2019
f23483c
Move write of pipxrc to end of install.
itsayellow Sep 24, 2019
00dcae9
Updates to install pipxrc behavior.
itsayellow Sep 24, 2019
8816177
Add notes to upgrade_all() to use pipxrc for args.
itsayellow Sep 24, 2019
ac192dd
Lint fixes for black.
itsayellow Sep 24, 2019
d66f56d
Remove obsolete TODO.
itsayellow Sep 24, 2019
fbe6dec
Make reinstall-all use each PKG original options.
itsayellow Sep 24, 2019
ba55fc5
Add update to pipxrc after upgrade.
itsayellow Sep 24, 2019
409d1c8
Make upgrade-all use each PKG's orig. options.
itsayellow Sep 24, 2019
06af0f8
Remove accidentally-left useless line.
itsayellow Sep 24, 2019
e3ce60e
Add pipxrc.pipxrc_info_template.
itsayellow Sep 26, 2019
3f9da7a
Add typing info for mypy.
itsayellow Sep 26, 2019
2b157d6
Change pipxrc_version from float to str.
itsayellow Sep 26, 2019
52c0a43
Convert pipxrc interface to class-based.
itsayellow Sep 26, 2019
c2a5ffb
New PipxrcInfo data class.
itsayellow Oct 1, 2019
bcf4ca7
Rename PipxrcInfo helpers non-private and better.
itsayellow Oct 1, 2019
3425fb2
Fix typing, remove obsolete import copy.
itsayellow Oct 1, 2019
9b705a1
Use InjPkg NamedTuple for injected_packages.
itsayellow Oct 1, 2019
4f97141
Use InstallOpts NamedTuple for install options.
itsayellow Oct 1, 2019
6b8a010
New _val_or_default() for get_ member fxns.
itsayellow Oct 1, 2019
d937266
Add typing, fix PipxrcInfo.to_dict error.
itsayellow Oct 1, 2019
d0a59e4
Fix formatting for black.
itsayellow Oct 1, 2019
692d414
Add _abs_path_if_local() for local pacakge paths.
itsayellow Oct 1, 2019
5f632b7
Clean up of _abs_path_if_local(). Add comments.
itsayellow Oct 2, 2019
59fcb19
Add more typing to _val_or_default().
itsayellow Oct 2, 2019
17776f9
Change pipxrc -> pipxrc.json, make pipx info filename a global.
itsayellow Oct 16, 2019
be0c2a9
Change abbreviated names to full names.
itsayellow Oct 18, 2019
ad4494c
Remove args from merge that were removed in upgrade_all and reinstall…
itsayellow Oct 18, 2019
f319263
Black reformat.
itsayellow Oct 18, 2019
49be1f4
Updated docs from new help.
itsayellow Oct 20, 2019
86b6ecb
Rename JsonEncoderPipx -> JsonEncoderHandlesPath.
itsayellow Oct 21, 2019
fb0a1d3
Log warning if failure to read or write pipxrc.json.
itsayellow Oct 21, 2019
ed53006
New comments, remove old TODO.
itsayellow Oct 21, 2019
2e0350b
Change get_injected_packages to return Dict[str,InjectedPackage]
itsayellow Oct 21, 2019
428b2f8
Add colon after TODO.
itsayellow Oct 22, 2019
cd02666
Resolved pip --editable TODO.
itsayellow Oct 22, 2019
d5dea0e
Remove TODO, keep _abs_path_if_local in commands.py.
itsayellow Oct 22, 2019
9a1dc0a
Move abs_path_if_local to pipxrc.
itsayellow Oct 25, 2019
2ed2911
Remove getter/setter, remove PipxrcInfo, refactor.
itsayellow Oct 25, 2019
2e6af1b
Init all member variables in Pipxrc.__init__()
itsayellow Oct 25, 2019
5a489fe
Fix last commit, dont redeclare types in reset.
itsayellow Oct 25, 2019
e594e89
Rename Pipxrc, PipxVenvMetadata objects.
itsayellow Oct 27, 2019
d21842c
Start moving pipxrc actions into Venv.py
itsayellow Oct 27, 2019
47ec960
Rearrange object locations to avoid circular imports.
itsayellow Oct 27, 2019
8b62ae1
Put package data from VenvMetadata in PackageInfo.
itsayellow Oct 27, 2019
2329fa8
Fix lint errors.
itsayellow Oct 27, 2019
3d43a78
Undo accidental commit.
itsayellow Oct 27, 2019
5562933
Move VenvMetadata back into Venv.py
itsayellow Oct 27, 2019
f7b32dd
Now only use pipx_metadata through venv.
itsayellow Oct 27, 2019
17a00a3
Add package_or_url to inject. Change PipxMetadata.
itsayellow Oct 27, 2019
fd515a3
Remove obsolete comment.
itsayellow Oct 27, 2019
a824147
Remove most venv.get_venv_metadata_for_package.
itsayellow Oct 27, 2019
25be4b0
Moving python_version check back to create_venv().
itsayellow Oct 27, 2019
9619dae
Update comment.
itsayellow Oct 27, 2019
7066ffc
Revert back to using old_package_metadata for include_dependencies.
itsayellow Oct 27, 2019
80ce2f0
Remove another get_venv_metadata_for_package().
itsayellow Oct 27, 2019
c1768c7
update_package_metadata(): Rename is_main to is_main_package.
itsayellow Oct 27, 2019
34d0455
Rename pipxrc.py -> pipx_metadata_file.py.
itsayellow Oct 27, 2019
fa5ccc6
Integrate Venv.update_package_metadata() in install().
itsayellow Oct 28, 2019
8afdfba
Enable install_package to determine package name.
itsayellow Oct 28, 2019
4278656
Add package name to PackageInfo.
itsayellow Oct 28, 2019
e9f64e6
Make run find package name or use empty string for install_package.
itsayellow Oct 28, 2019
d58887d
Change package_metadata to get name of main_package from PackageInfo.
itsayellow Oct 28, 2019
198141e
In Venv move update_package_metadata into upgrade_package.
itsayellow Oct 28, 2019
17d241f
Simplify code of update_package_metadata().
itsayellow Oct 29, 2019
d61fa62
Start of test_pipx_metadata_file.py.
itsayellow Oct 30, 2019
5f2040e
Clarify comment.
itsayellow Oct 30, 2019
c4f44aa
Comment false assert.
itsayellow Oct 30, 2019
12c82a7
Add temp_path fixture.
itsayellow Oct 30, 2019
a86d0dd
Add mock PackageInfo to test.
itsayellow Oct 30, 2019
314e733
More tests.
itsayellow Oct 31, 2019
c727870
Add another test to validate_before_write().
itsayellow Oct 31, 2019
d73819d
Add more file validation testing.
itsayellow Oct 31, 2019
4fb7da3
Simplify test package creation.
itsayellow Oct 31, 2019
7c4daa6
Add test of package install.
itsayellow Nov 2, 2019
226389f
Fix rebase miss: pipx_metadata_file.py in wrong place.
itsayellow Nov 4, 2019
4240012
Merge branch 'master' of https://github.com/pipxproject/pipx
itsayellow Nov 4, 2019
b16d30f
Rename update_package_metadata -> _update_package_metadata.
itsayellow Nov 4, 2019
01abd31
Rename validate_before_write -> _validate_before_write.
itsayellow Nov 4, 2019
84846bb
Remove spurious comments.
itsayellow Nov 4, 2019
1ab8743
Merge branch 'master' of https://github.com/pipxproject/pipx
Nov 4, 2019
205cc94
Use fixture pipx_temp_env for installing.
itsayellow Nov 4, 2019
ff3cd5e
Fix bug specifying pipx_home.
itsayellow Nov 4, 2019
3d51c4a
Add install and inject metadata tests.
itsayellow Nov 4, 2019
c7dbdb5
Add noqa to asserts for flake8.
itsayellow Nov 4, 2019
2c2189f
Fix expected pacakge metadata for Windows.
itsayellow Nov 4, 2019
6313d0d
Remove obsolete TODO.
itsayellow Nov 4, 2019
d6dcf42
Add Windows fixes.
itsayellow Nov 4, 2019
ffbcc6c
Merge branch 'master' of https://github.com/pipxproject/pipx
itsayellow Nov 4, 2019
ba67fcb
Dont depend on order of list items when it is not important.
itsayellow Nov 4, 2019
844b17b
Merge branch 'master' of https://github.com/pipxproject/pipx
itsayellow Nov 4, 2019
daa0d24
Merge branch 'master' of https://github.com/pipxproject/pipx
itsayellow Nov 4, 2019
48ba85c
Merge branch 'master' of https://github.com/pipxproject/pipx
itsayellow Nov 5, 2019
b79b6b4
Merge part 2, fix other conflict.
itsayellow Nov 5, 2019
25a9fd5
Merge part3, put missing python error back in _get_package_summary.
itsayellow Nov 5, 2019
f8eb816
Remove --spec from pipx upgrade.
itsayellow Nov 5, 2019
6379abd
Remove --include-deps as option for upgrade.
itsayellow Nov 5, 2019
a91e3ab
Fix upgrade_all instantiation of upgrade, clean up upgrade.
itsayellow Nov 5, 2019
42b6b35
Remove TODO, add clarifying comment.
itsayellow Nov 6, 2019
a75f814
Remove obsolete TODOs.
itsayellow Nov 6, 2019
6601b28
Simplify code using property from venv.
itsayellow Nov 6, 2019
e83f100
Merge branch 'master' of https://github.com/pipxproject/pipx
itsayellow Nov 12, 2019
a80c747
Pass None to Venv.install_package in package if it is unknown.
itsayellow Nov 12, 2019
9d5ea3f
Move uninstall closer to install.
itsayellow Nov 12, 2019
7e2138c
Remove constant PIPX_PACKAGE_NAME, replace in code with "pipx".
itsayellow Nov 12, 2019
8d741ba
Streamline pip_search cmd list creation.
itsayellow Nov 12, 2019
f744c43
Add typing information to return values.
itsayellow Nov 12, 2019
096dddb
Remove unnecessary comment.
itsayellow Nov 12, 2019
be80ce0
Remove top_package_name, simplify code.
itsayellow Nov 13, 2019
da3e58b
Use is False/True to get rid of noqa.
itsayellow Nov 13, 2019
e9a992d
Simplify test_pipx_metadata_file_create.
itsayellow Nov 13, 2019
2792205
Remove self.reset if read fails.
itsayellow Nov 13, 2019
fd2aaec
Parametrize test_pipx_metadata_file_validation.
itsayellow Nov 13, 2019
faa6a8b
Print stderr for test_run_ensure_null_pythonpath to diagnose.
itsayellow Nov 13, 2019
01199f3
Add TODO about Issue #217 in test_package_install.
itsayellow Nov 13, 2019
6b9e138
Revert "Print stderr for test_run_ensure_null_pythonpath to diagnose."
itsayellow Nov 13, 2019
bbb6f66
Another try to diagnose Windows test_run problem.
itsayellow Nov 13, 2019
f4fb258
Revert "Another try to diagnose Windows test_run problem."
itsayellow Nov 13, 2019
a9f4d14
REVERT ME: to test Windows CI failures.
itsayellow Nov 13, 2019
a7089be
REVERT ME: to test Windows CI failures2.
itsayellow Nov 13, 2019
bc78e21
REVERT ME: to test Windows CI failures3.
itsayellow Nov 13, 2019
02678c6
REVERT ME: to test Windows CI failures4.
itsayellow Nov 13, 2019
b4f6a03
Revert "REVERT ME: to test Windows CI failures4."
itsayellow Nov 13, 2019
e75e099
Revert "REVERT ME: to test Windows CI failures3."
itsayellow Nov 13, 2019
d530961
Revert "REVERT ME: to test Windows CI failures2."
itsayellow Nov 13, 2019
ab7281c
Revert "REVERT ME: to test Windows CI failures."
itsayellow Nov 13, 2019
80b6792
Add universal_newlines=True to subprocess.run.
itsayellow Nov 13, 2019
e367e1b
Streamline test_package_install.
itsayellow Nov 14, 2019
685e9a2
Black reformat.
itsayellow Nov 14, 2019
72d9f3d
Make app_paths placeholder a valid Path.
itsayellow Nov 14, 2019
5bfb985
Fix test_package_install for windows.
itsayellow Nov 14, 2019
4de5bdb
Merge branch 'master' of github.com:itsayellow/pipx
itsayellow Nov 14, 2019
5aa1b57
Compare sets not lists in assert_package_metadata.
itsayellow Nov 14, 2019
52d8567
Split test_package_inject from test_package_install.
itsayellow Nov 14, 2019
7b67b78
Change keys() assertion to list to be compatible with dict_keys.
itsayellow Nov 14, 2019
689a90f
Make extra time on check_animate_output 0.5 seconds.
itsayellow Nov 14, 2019
2edb95e
New improved method for package name determination.
itsayellow Nov 15, 2019
6341b9c
Remove Iterable from typing import.
itsayellow Nov 15, 2019
6308136
Add test for package name determination.
itsayellow Nov 15, 2019
346931d
Clean up test_package_determination code.
itsayellow Nov 15, 2019
aa1544e
Clean up test_package_determination code 2.
itsayellow Nov 15, 2019
e829ea0
Add and use util.run_stdout_stderr.
itsayellow Nov 15, 2019
be2f62b
Convert more subprocess.run calls to run_stdout_stderr.
itsayellow Nov 15, 2019
f4a8968
Change run_stdout_stderr to run_subprocess, use inside of run.
itsayellow Nov 15, 2019
1ec7959
Fix typo in comment.
itsayellow Nov 15, 2019
0011da2
Fix bug in run, misnamed variable.
itsayellow Nov 15, 2019
d11a7d5
Refine TODOs, add Issue for tracking.
itsayellow Nov 15, 2019
6f621ac
Add cmd_str for error message in run().
itsayellow Nov 15, 2019
1a0035f
Add comment explaining why we delete PYTHONPATH.
itsayellow Nov 15, 2019
adfad97
Merge remote-tracking branch 'upstream/master'
itsayellow Nov 29, 2019
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
35 changes: 4 additions & 31 deletions docs/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,25 +206,13 @@ optional arguments:

```
pipx upgrade-all --help
usage: pipx upgrade-all [-h] [--include-deps] [--system-site-packages]
[--index-url INDEX_URL] [--editable]
[--pip-args PIP_ARGS] [--skip SKIP [SKIP ...]]
[--force] [--verbose]
usage: pipx upgrade-all [-h] [--skip SKIP [SKIP ...]] [--force] [--verbose]

Upgrades all packages within their virtual environments by running 'pip
install --upgrade PACKAGE'

optional arguments:
-h, --help show this help message and exit
--include-deps Include apps of dependent packages
--system-site-packages
Give the virtual environment access to the system
site-packages dir.
--index-url INDEX_URL, -i INDEX_URL
Base URL of Python Package Index
--editable, -e Install a project in editable mode
--pip-args PIP_ARGS Arbitrary pip arguments to pass directly to pip
install/upgrade commands
--skip SKIP [SKIP ...]
skip these packages
--force, -f Modify existing virtual environment and files in
Expand Down Expand Up @@ -307,35 +295,20 @@ optional arguments:

```
pipx reinstall-all --help
usage: pipx reinstall-all [-h] [--include-deps] [--system-site-packages]
[--index-url INDEX_URL] [--editable]
[--pip-args PIP_ARGS] [--skip SKIP [SKIP ...]]
[--verbose]
python
usage: pipx reinstall-all [-h] [--skip SKIP [SKIP ...]] [--verbose] python

Reinstalls all packages using a different version of Python.

Packages are uninstalled, then installed with pipx install PACKAGE.
Packages are uninstalled, then installed with pipx install PACKAGE
with the same options used in the original install of PACKAGE.
This is useful if you upgraded to a new version of Python and want
all your packages to use the latest as well.

If you originally installed a package from a source other than PyPI,
this command may behave in unexpected ways since it will reinstall from PyPI.

positional arguments:
python

optional arguments:
-h, --help show this help message and exit
--include-deps Include apps of dependent packages
--system-site-packages
Give the virtual environment access to the system
site-packages dir.
--index-url INDEX_URL, -i INDEX_URL
Base URL of Python Package Index
--editable, -e Install a project in editable mode
--pip-args PIP_ARGS Arbitrary pip arguments to pass directly to pip
install/upgrade commands
--skip SKIP [SKIP ...]
skip these packages
--verbose
Expand Down
185 changes: 134 additions & 51 deletions src/pipx/commands/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
rmdir,
run_pypackage_bin,
)
from pipx.venv import Venv, VenvContainer
from pipx.venv import Venv, VenvContainer, PackageInstallFailureError


def run(
Expand Down Expand Up @@ -126,7 +126,7 @@ def run(

def _download_and_run(
venv_dir: Path,
package: str,
package_or_url: str,
app: str,
binary_args: List[str],
python: str,
Expand All @@ -136,12 +136,27 @@ def _download_and_run(
):
venv = Venv(venv_dir, python=python, verbose=verbose)
venv.create_venv(venv_args, pip_args)
venv.install_package(package, pip_args)

# venv.pipx_metadata.main_package.package contains package name if it is
# pre-existing, otherwise is None to instruct venv.install_package to
# determine package name.

try:
venv.install_package(
package=venv.pipx_metadata.main_package.package,
package_or_url=package_or_url,
pip_args=pip_args,
include_dependencies=False,
include_apps=True,
is_main_package=True,
)
except PackageInstallFailureError:
raise PipxError(f"Unable to install {package_or_url}")

if not (venv.bin_path / app).exists():
apps = venv.get_venv_metadata_for_package(package).apps
apps = venv.pipx_metadata.main_package.apps
raise PipxError(
f"'{app}' executable script not found in package '{package}'. "
f"'{app}' executable script not found in package '{package_or_url}'. "
"Available executable scripts: "
f"{', '.join(b for b in apps)}"
)
Expand Down Expand Up @@ -229,11 +244,20 @@ def install(
venv = Venv(venv_dir, python=python, verbose=verbose)
try:
venv.create_venv(venv_args, pip_args)
venv.install_package(package_or_url, pip_args)

if venv.get_venv_metadata_for_package(package).package_version is None:
try:
venv.install_package(
package=package,
package_or_url=package_or_url,
pip_args=pip_args,
include_dependencies=include_dependencies,
include_apps=True,
is_main_package=True,
)
except PackageInstallFailureError:
venv.remove_venv()
raise PipxError(f"Could not find package {package}. Is the name correct?")
raise PipxError(
f"Could not install package {package}. Is the name or spec correct?"
)

_run_post_install_actions(
venv, package, local_bin_dir, venv_dir, include_dependencies, force=force
Expand All @@ -253,12 +277,12 @@ def _run_post_install_actions(
*,
force: bool,
):
metadata = venv.get_venv_metadata_for_package(package)
package_metadata = venv.package_metadata[package]

if not metadata.app_paths and not include_dependencies:
if not package_metadata.app_paths and not include_dependencies:
# No apps associated with this package and we aren't including dependencies.
# This package has nothing for pipx to use, so this is an error.
for dep, dependent_apps in metadata.app_paths_of_dependencies.items():
for dep, dependent_apps in package_metadata.app_paths_of_dependencies.items():
print(
f"Note: Dependent package '{dep}' contains {len(dependent_apps)} apps"
)
Expand All @@ -268,7 +292,7 @@ def _run_post_install_actions(
if venv.safe_to_remove():
venv.remove_venv()

if len(metadata.app_paths_of_dependencies.keys()):
if len(package_metadata.app_paths_of_dependencies.keys()):
raise PipxError(
f"No apps associated with package {package}. "
"Try again with '--include-deps' to include apps of dependent packages, "
Expand All @@ -283,9 +307,9 @@ def _run_post_install_actions(
"Consider using pip or a similar tool instead."
)

if metadata.apps:
if package_metadata.apps:
pass
elif metadata.apps_of_dependencies and include_dependencies:
elif package_metadata.apps_of_dependencies and include_dependencies:
pass
else:
# No apps associated with this package and we aren't including dependencies.
Expand All @@ -298,10 +322,12 @@ def _run_post_install_actions(
"Consider using pip or a similar tool instead."
)

_expose_apps_globally(local_bin_dir, metadata.app_paths, package, force=force)
_expose_apps_globally(
local_bin_dir, package_metadata.app_paths, package, force=force
)

if include_dependencies:
for _, app_paths in metadata.app_paths_of_dependencies.items():
for _, app_paths in package_metadata.app_paths_of_dependencies.items():
_expose_apps_globally(local_bin_dir, app_paths, package, force=force)

print(_get_package_summary(venv_dir, package=package, new_install=True))
Expand All @@ -323,6 +349,7 @@ def _warn_if_not_on_path(local_bin_dir: Path):
def inject(
venv_dir: Path,
package: str,
package_or_url: str,
pip_args: List[str],
*,
verbose: bool,
Expand All @@ -341,8 +368,19 @@ def inject(
)

venv = Venv(venv_dir, verbose=verbose)
venv.install_package(package, pip_args)

try:
venv.install_package(
package=package,
package_or_url=package_or_url,
pip_args=pip_args,
include_dependencies=include_dependencies,
include_apps=include_apps,
is_main_package=False,
)
except PackageInstallFailureError:
raise PipxError(
f"Could not inject package {package}. Is the name or spec correct?"
)
if include_apps:
_run_post_install_actions(
venv,
Expand All @@ -358,6 +396,9 @@ def inject(


def uninstall(venv_dir: Path, package: str, local_bin_dir: Path, verbose: bool):
"""Uninstall entire venv_dir, including main package and all injected
packages.
"""
if not venv_dir.exists():
print(f"Nothing to uninstall for {package} 😴")
app = which(package)
Expand All @@ -369,27 +410,35 @@ def uninstall(venv_dir: Path, package: str, local_bin_dir: Path, verbose: bool):

venv = Venv(venv_dir, verbose=verbose)

if venv.python_path.is_file():
# has a valid python interpreter and can get metadata about the package
metadata = venv.get_venv_metadata_for_package(package)
app_paths = metadata.app_paths
for dep_paths in metadata.app_paths_of_dependencies.values():
app_paths += dep_paths
if venv.pipx_metadata.main_package is not None:
app_paths: List[Path] = []
for viewed_package in venv.package_metadata.values():
app_paths += viewed_package.app_paths
for dep_paths in viewed_package.app_paths_of_dependencies.values():
app_paths += dep_paths
else:
# Doesn't have a valid python interpreter. We'll take our best guess on what to uninstall
# here based on symlink location. pipx doesn't use symlinks on windows, so this is for
# non-windows only.
# The heuristic here is any symlink in ~/.local/bin pointing to .local/pipx/venvs/PACKAGE/bin
# should be uninstalled.
if WINDOWS:
app_paths = []
# fallback if not metadata from pipx_metadata.json
if venv.python_path.is_file():
# has a valid python interpreter and can get metadata about the package
metadata = venv.get_venv_metadata_for_package(package)
app_paths = metadata.app_paths
for dep_paths in metadata.app_paths_of_dependencies.values():
app_paths += dep_paths
else:
apps_linking_to_venv_bin_dir = [
f
for f in constants.LOCAL_BIN_DIR.iterdir()
if str(f.resolve()).startswith(str(venv.bin_path))
]
app_paths = apps_linking_to_venv_bin_dir
# Doesn't have a valid python interpreter. We'll take our best guess on what to uninstall
# here based on symlink location. pipx doesn't use symlinks on windows, so this is for
# non-windows only.
# The heuristic here is any symlink in ~/.local/bin pointing to .local/pipx/venvs/PACKAGE/bin
# should be uninstalled.
if WINDOWS:
app_paths = []
else:
apps_linking_to_venv_bin_dir = [
f
for f in constants.LOCAL_BIN_DIR.iterdir()
if str(f.resolve()).startswith(str(venv.bin_path))
]
app_paths = apps_linking_to_venv_bin_dir

for file in local_bin_dir.iterdir():
if WINDOWS:
Expand Down Expand Up @@ -417,33 +466,58 @@ def reinstall_all(
venv_container: VenvContainer,
local_bin_dir: Path,
python: str,
pip_args: List[str],
venv_args: List[str],
verbose: bool,
include_dependencies: bool,
*,
skip: List[str],
):
for venv_dir in venv_container.iter_venv_dirs():
package = venv_dir.name
if package in skip:
continue

venv = Venv(venv_dir, verbose=verbose)

if venv.pipx_metadata.main_package.package_or_url is not None:
package_or_url = venv.pipx_metadata.main_package.package_or_url
else:
package_or_url = package

uninstall(venv_dir, package, local_bin_dir, verbose)

package_or_url = package
# install main package first
install(
venv_dir,
package,
package_or_url,
local_bin_dir,
python,
pip_args,
venv_args,
venv.pipx_metadata.main_package.pip_args,
venv.pipx_metadata.venv_args,
verbose,
force=True,
include_dependencies=include_dependencies,
include_dependencies=venv.pipx_metadata.main_package.include_dependencies,
)

# now install injected packages
for (
injected_name,
injected_package,
) in venv.pipx_metadata.injected_packages.items():
if injected_package.package_or_url is None:
# This should never happen, but package_or_url is type
# Optional[str] so mypy thinks it could be None
raise PipxError("Internal Error injecting package")
inject(
venv_dir,
injected_name,
injected_package.package_or_url,
injected_package.pip_args,
verbose=verbose,
include_apps=injected_package.include_apps,
include_dependencies=injected_package.include_dependencies,
force=True,
)


def _expose_apps_globally(
local_bin_dir: Path, app_paths: List[Path], package: str, *, force: bool
Expand Down Expand Up @@ -524,22 +598,31 @@ def _get_package_summary(
if not python_path.is_file():
return f" package {red(bold(package))} has invalid interpreter {str(python_path)}"

metadata = venv.get_venv_metadata_for_package(package)
package_metadata = venv.package_metadata[package]

if metadata.package_version is None:
if package_metadata.package_version is None:
not_installed = red("is not installed")
return f" package {bold(package)} {not_installed} in the venv {str(path)}"

apps = metadata.apps + metadata.apps_of_dependencies
apps = package_metadata.apps + package_metadata.apps_of_dependencies
exposed_app_paths = _get_exposed_app_paths_for_package(
venv.bin_path, apps, constants.LOCAL_BIN_DIR
)
exposed_binary_names = sorted(p.name for p in exposed_app_paths)
unavailable_binary_names = sorted(set(metadata.apps) - set(exposed_binary_names))
unavailable_binary_names = sorted(
set(package_metadata.apps) - set(exposed_binary_names)
)
# The following is to satisfy mypy that python_version is str and not
# Optional[str]
python_version = (
venv.pipx_metadata.python_version
if venv.pipx_metadata.python_version is not None
else ""
)
return _get_list_output(
metadata.python_version,
python_version,
python_path,
metadata.package_version,
package_metadata.package_version,
package,
new_install,
exposed_binary_names,
Expand Down
Loading