Skip to content
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
12 changes: 11 additions & 1 deletion src/pipx/commands/inject.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ def inject_dep(
include_apps: bool,
include_dependencies: bool,
force: bool,
upgrade: bool,
upgrade_strategy: Optional[str],
suffix: bool = False,
) -> bool:
logger.debug("Injecting package %s", package_spec)
Expand Down Expand Up @@ -64,7 +66,11 @@ def inject_dep(
verbose=verbose,
)

if not force and venv.has_package(package_name):
if upgrade:
pip_args = ["--upgrade"] + pip_args
if upgrade_strategy is not None:
pip_args += ["--upgrade-strategy", upgrade_strategy]
elif not force and venv.has_package(package_name):
logger.info("Package %s has already been injected", package_name)
print(
pipx_wrap(
Expand Down Expand Up @@ -119,6 +125,8 @@ def inject(
include_apps: bool,
include_dependencies: bool,
force: bool,
upgrade: bool,
upgrade_strategy: Optional[str],
suffix: bool = False,
) -> ExitCode:
"""Returns pipx exit code."""
Expand Down Expand Up @@ -148,6 +156,8 @@ def inject(
include_apps=include_apps,
include_dependencies=include_dependencies,
force=force,
upgrade=upgrade,
upgrade_strategy=upgrade_strategy,
suffix=suffix,
)

Expand Down
14 changes: 13 additions & 1 deletion src/pipx/commands/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ def install(
verbose: bool,
*,
force: bool,
upgrade: bool,
upgrade_strategy: Optional[str],
reinstall: bool,
include_dependencies: bool,
preinstall_packages: Optional[List[str]],
Expand Down Expand Up @@ -60,7 +62,11 @@ def install(

venv = Venv(venv_dir, python=python, verbose=verbose)
venv.check_upgrade_shared_libs(pip_args=pip_args, verbose=verbose)
if exists:
if upgrade:
pip_args = ["--upgrade"] + pip_args
if upgrade_strategy is not None:
pip_args += ["--upgrade-strategy", upgrade_strategy]
elif exists:
if not reinstall and force and python_flag_passed:
print(
pipx_wrap(
Expand Down Expand Up @@ -103,6 +109,8 @@ def install(
include_dependencies=include_dependencies,
include_apps=True,
is_main_package=True,
upgrade=upgrade,
upgrade_strategy=upgrade_strategy,
suffix=suffix,
)
run_post_install_actions(
Expand Down Expand Up @@ -213,6 +221,8 @@ def install_all(
reinstall=False,
include_dependencies=main_package.include_dependencies,
preinstall_packages=[],
upgrade=False,
upgrade_strategy=None,
suffix=main_package.suffix,
)

Expand All @@ -228,6 +238,8 @@ def install_all(
include_apps=inject_package.include_apps,
include_dependencies=inject_package.include_dependencies,
force=force,
upgrade=False,
upgrade_strategy=None,
suffix=inject_package.suffix == main_package.suffix,
)
except PipxError as e:
Expand Down
2 changes: 2 additions & 0 deletions src/pipx/commands/reinstall.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ def reinstall(
verbose=verbose,
include_apps=injected_package.include_apps,
include_dependencies=injected_package.include_dependencies,
upgrade=False,
upgrade_strategy=None,
force=True,
)

Expand Down
2 changes: 2 additions & 0 deletions src/pipx/commands/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ def _download_and_run(
pip_args=pip_args,
include_dependencies=False,
include_apps=True,
upgrade=False,
upgrade_strategy=None,
is_main_package=True,
)

Expand Down
9 changes: 9 additions & 0 deletions src/pipx/commands/upgrade.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def _upgrade_package(
pip_args: List[str],
is_main_package: bool,
force: bool,
upgrade_strategy: Optional[str],
upgrading_all: bool,
) -> int:
"""Returns 1 if package version changed, 0 if same version"""
Expand Down Expand Up @@ -49,6 +50,7 @@ def _upgrade_package(
include_dependencies=package_metadata.include_dependencies,
include_apps=package_metadata.include_apps,
is_main_package=is_main_package,
upgrade_strategy=upgrade_strategy,
suffix=package_metadata.suffix,
)

Expand Down Expand Up @@ -111,6 +113,7 @@ def _upgrade_venv(
*,
include_injected: bool,
upgrading_all: bool,
upgrade_strategy: Optional[str],
force: bool,
install: bool = False,
venv_args: Optional[List[str]] = None,
Expand Down Expand Up @@ -177,6 +180,7 @@ def _upgrade_venv(
is_main_package=True,
force=force,
upgrading_all=upgrading_all,
upgrade_strategy=upgrade_strategy,
)

if include_injected:
Expand All @@ -190,6 +194,7 @@ def _upgrade_venv(
is_main_package=False,
force=force,
upgrading_all=upgrading_all,
upgrade_strategy=upgrade_strategy,
)

return versions_updated
Expand All @@ -205,6 +210,7 @@ def upgrade(
include_injected: bool,
force: bool,
install: bool,
upgrade_strategy: Optional[str],
python_flag_passed: bool = False,
) -> ExitCode:
"""Return pipx exit code."""
Expand All @@ -218,6 +224,7 @@ def upgrade(
upgrading_all=False,
force=force,
install=install,
upgrade_strategy=upgrade_strategy,
venv_args=venv_args,
python=python,
python_flag_passed=python_flag_passed,
Expand All @@ -236,6 +243,7 @@ def upgrade_all(
skip: Sequence[str],
force: bool,
python_flag_passed: bool = False,
upgrade_strategy: Optional[str],
) -> ExitCode:
"""Return pipx exit code."""
failed: List[str] = []
Expand All @@ -253,6 +261,7 @@ def upgrade_all(
verbose=verbose,
include_injected=include_injected,
upgrading_all=True,
upgrade_strategy=upgrade_strategy,
force=force,
python_flag_passed=python_flag_passed,
)
Expand Down
60 changes: 60 additions & 0 deletions src/pipx/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,8 @@ def run_pipx_command(args: argparse.Namespace, subparsers: Dict[str, argparse.Ar
venv_args,
verbose,
force=args.force,
upgrade=args.upgrade,
upgrade_strategy=args.upgrade_strategy,
reinstall=False,
include_dependencies=args.include_deps,
preinstall_packages=args.preinstall,
Expand Down Expand Up @@ -318,6 +320,8 @@ def run_pipx_command(args: argparse.Namespace, subparsers: Dict[str, argparse.Ar
include_apps=args.include_apps,
include_dependencies=args.include_deps,
force=args.force,
upgrade=args.upgrade,
upgrade_strategy=args.upgrade_strategy,
suffix=args.with_suffix,
)
elif args.command == "uninject":
Expand All @@ -340,6 +344,7 @@ def run_pipx_command(args: argparse.Namespace, subparsers: Dict[str, argparse.Ar
force=args.force,
install=args.install,
python_flag_passed=python_flag_passed,
upgrade_strategy=args.upgrade_strategy,
)
elif args.command == "upgrade-all":
return commands.upgrade_all(
Expand All @@ -350,6 +355,7 @@ def run_pipx_command(args: argparse.Namespace, subparsers: Dict[str, argparse.Ar
force=args.force,
pip_args=pip_args,
python_flag_passed=python_flag_passed,
upgrade_strategy=args.upgrade_strategy,
)
elif args.command == "upgrade-shared":
return commands.upgrade_shared(
Expand Down Expand Up @@ -501,6 +507,22 @@ def _add_install(subparsers: argparse._SubParsersAction, shared_parser: argparse
"installing the main package. Use this flag multiple times if you want to preinstall multiple packages."
),
)
p.add_argument(
"--upgrade",
action="store_true",
help="Upgrade packages if already installed with `pip install --upgrade`",
)
p.add_argument(
"--upgrade-strategy",
nargs=1,
choices=["eager", "only-if-needed"],
help=(
"Determines how dependency upgrading is handled. "
'"eager" upgrades all dependencies regardless of whether version requirements are satisfied by the main package. '
'"only-if-needed" upgrades dependencies only when they do not satisfy requirements. '
'Default "only-if-needed" if --upgrade is provided. Ignored if --upgrade is not specified.'
),
)
add_pip_venv_args(p)


Expand Down Expand Up @@ -569,6 +591,22 @@ def _add_inject(subparsers, venv_completer: VenvCompleter, shared_parser: argpar
action="store_true",
help="Modify existing virtual environment and files in PIPX_BIN_DIR and PIPX_MAN_DIR",
)
p.add_argument(
"--upgrade",
action="store_true",
help="Upgrade packages if already installed with `pip install --upgrade`",
)
p.add_argument(
"--upgrade-strategy",
nargs=1,
choices=["eager", "only-if-needed"],
help=(
"Determines how dependency upgrading is handled. "
'"eager" upgrades all dependencies regardless of whether version requirements are satisfied by the main package. '
'"only-if-needed" upgrades dependencies only when they do not satisfy requirements. '
'Default "only-if-needed" if --upgrade is provided. Ignored if --upgrade is not specified.'
),
)
p.add_argument(
"--with-suffix",
action="store_true",
Expand Down Expand Up @@ -658,6 +696,17 @@ def _add_upgrade(subparsers, venv_completer: VenvCompleter, shared_parser: argpa
action="store_true",
help="Install package spec if missing",
)
p.add_argument(
"--upgrade-strategy",
nargs=1,
choices=["eager", "only-if-needed"],
help=(
"Determines how dependency upgrading is handled. "
'"eager" upgrades all dependencies regardless of whether version requirements are satisfied by the main package. '
'"only-if-needed" upgrades dependencies only when they do not satisfy requirements. '
'Default "only-if-needed" if --upgrade is provided. Ignored if --upgrade is not specified.'
),
)
add_python_options(p)


Expand All @@ -680,6 +729,17 @@ def _add_upgrade_all(subparsers: argparse._SubParsersAction, shared_parser: argp
action="store_true",
help="Modify existing virtual environment and files in PIPX_BIN_DIR and PIPX_MAN_DIR",
)
p.add_argument(
"--upgrade-strategy",
nargs=1,
choices=["eager", "only-if-needed"],
help=(
"Determines how dependency upgrading is handled. "
'"eager" upgrades all dependencies regardless of whether version requirements are satisfied by the main package. '
'"only-if-needed" upgrades dependencies only when they do not satisfy requirements. '
'Default "only-if-needed" if --upgrade is provided. Ignored if --upgrade is not specified.'
),
)


def _add_upgrade_shared(subparsers: argparse._SubParsersAction, shared_parser: argparse.ArgumentParser) -> None:
Expand Down
3 changes: 3 additions & 0 deletions src/pipx/venv.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,9 +452,12 @@ def upgrade_package(
include_dependencies: bool,
include_apps: bool,
is_main_package: bool,
upgrade_strategy: Optional[str],
suffix: str = "",
) -> None:
logger.info("Upgrading %s", package_descr := full_package_description(package_name, package_or_url))
if upgrade_strategy is not None:
pip_args += ["--upgrade-strategy", upgrade_strategy]
with animate(f"upgrading {package_descr}", self.do_animation):
pip_process = self._run_pip(["--no-input", "install", "--upgrade"] + pip_args + [package_or_url])
subprocess_post_check(pip_process)
Expand Down