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

pipx install: emit a warning when --force and --python were passed at the same time #899

Merged
merged 8 commits into from
Nov 30, 2023
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## dev

- `pipx install`: emit a warning when `--force` and `--python` were passed at the same time
- Drop support for Python 3.7
- 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
Expand Down
17 changes: 16 additions & 1 deletion src/pipx/commands/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from pipx import constants
from pipx.commands.common import package_name_from_spec, run_post_install_actions
from pipx.constants import EXIT_CODE_INSTALL_VENV_EXISTS, EXIT_CODE_OK, ExitCode
from pipx.interpreter import DEFAULT_PYTHON
from pipx.util import pipx_wrap
from pipx.venv import Venv, VenvContainer

Expand All @@ -13,19 +14,23 @@ def install(
package_name: Optional[str],
package_spec: str,
local_bin_dir: Path,
python: str,
python: Optional[str],
pip_args: List[str],
venv_args: List[str],
verbose: bool,
*,
force: bool,
reinstall: bool,
include_dependencies: bool,
preinstall_packages: Optional[List[str]],
suffix: str = "",
) -> ExitCode:
"""Returns pipx exit code."""
# package_spec is anything pip-installable, including package_name, vcs spec,
# zip file, or tar.gz file.
python_flag_was_passed = python is not None

python = python or DEFAULT_PYTHON

if package_name is None:
package_name = package_name_from_spec(
Expand All @@ -42,6 +47,16 @@ def install(

venv = Venv(venv_dir, python=python, verbose=verbose)
if exists:
if not reinstall and force and python_flag_was_passed:
print(
pipx_wrap(
f"""
--python is ignored when --force is passed.
If you want to reinstall {package_name} with {python},
run `pipx reinstall {package_spec} --python {python}` instead.
"""
)
)
if force:
print(f"Installing to existing venv {venv.name!r}")
pip_args += ["--force-reinstall"]
Expand Down
1 change: 1 addition & 0 deletions src/pipx/commands/reinstall.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def reinstall(
venv.pipx_metadata.venv_args,
verbose,
force=True,
reinstall=True,
include_dependencies=venv.pipx_metadata.main_package.include_dependencies,
preinstall_packages=[],
suffix=venv.pipx_metadata.main_package.suffix,
Expand Down
3 changes: 2 additions & 1 deletion src/pipx/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ def run_pipx_command(args: argparse.Namespace) -> ExitCode: # noqa: C901
venv_args,
verbose,
force=args.force,
reinstall=False,
include_dependencies=args.include_deps,
preinstall_packages=args.preinstall,
suffix=args.suffix,
Expand Down Expand Up @@ -344,7 +345,7 @@ def _add_install(subparsers: argparse._SubParsersAction) -> None:
)
p.add_argument(
"--python",
default=DEFAULT_PYTHON,
# Don't pass a default Python here so we know whether --python flag was passed
help=(
"Python to install with. Possible values can be the executable name (python3.11), "
"the version to pass to py launcher (3.11), or the full path to the executable."
Expand Down
11 changes: 11 additions & 0 deletions tests/test_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,3 +284,14 @@ def test_preinstall(pipx_temp_env, caplog):
def test_do_not_wait_for_input(pipx_temp_env, pipx_session_shared_dir, monkeypatch):
monkeypatch.setenv("PIP_INDEX_URL", "http://127.0.0.1:8080/simple")
run_pipx_cli(["install", "pycowsay"])


def test_passed_python_and_force_flag_warning(pipx_temp_env, capsys):
assert not run_pipx_cli(["install", "black"])
assert not run_pipx_cli(["install", "--python", sys.executable, "--force", "black"])
captured = capsys.readouterr()
assert "--python is ignored when --force is passed." in captured.out

assert not run_pipx_cli(["install", "pycowsay", "--force"])
captured = capsys.readouterr()
assert "--python is ignored when --force is passed." not in captured.out