diff --git a/changelog.d/1324.bugfix.md b/changelog.d/1324.bugfix.md new file mode 100644 index 0000000000..3312909d61 --- /dev/null +++ b/changelog.d/1324.bugfix.md @@ -0,0 +1 @@ +Don't allow paths to be passed into `pipx reinstall`, as this might wreak havoc. diff --git a/src/pipx/main.py b/src/pipx/main.py index cee9df3569..c49f2d31ed 100644 --- a/src/pipx/main.py +++ b/src/pipx/main.py @@ -185,7 +185,8 @@ def run_pipx_command(args: argparse.Namespace, subparsers: Dict[str, argparse.Ar if "package" in args: package = args.package - if urllib.parse.urlparse(package).scheme: + url_parse_package = urllib.parse.urlparse(package) + if url_parse_package.scheme and url_parse_package.netloc: raise PipxError("Package cannot be a url") if "spec" in args and args.spec is not None: @@ -193,6 +194,20 @@ def run_pipx_command(args: argparse.Namespace, subparsers: Dict[str, argparse.Ar if "#egg=" not in args.spec: args.spec = args.spec + f"#egg={package}" + if args.command == "reinstall": + # Passing paths into `reinstall` might have unintended + # side effects. + if Path(package).is_absolute() or Path(package).exists(): + raise PipxError( + pipx_wrap( + f""" + Error: Path '{package}' given as + package. Expected the name of + an installed package. + """ + ) + ) + venv_dir = venv_container.get_venv_dir(package) logger.info(f"Virtual Environment location is {venv_dir}") diff --git a/tests/test_reinstall.py b/tests/test_reinstall.py index 38f013ff25..b049c2f78e 100644 --- a/tests/test_reinstall.py +++ b/tests/test_reinstall.py @@ -54,3 +54,17 @@ def test_reinstall_specifier(pipx_temp_env, capsys): assert not run_pipx_cli(["reinstall", "--python", sys.executable, "pylint"]) captured = capsys.readouterr() assert "installed package pylint 2.3.1" in captured.out + + +def test_reinstall_with_path(pipx_temp_env, capsys, tmp_path): + path = tmp_path / "some" / "path" + + assert run_pipx_cli(["reinstall", str(path)]) + captured = capsys.readouterr() + + assert "Expected the name of an installed package" in captured.err.replace("\n", " ") + + assert run_pipx_cli(["reinstall", str(path.resolve())]) + captured = capsys.readouterr() + + assert "Expected the name of an installed package" in captured.err.replace("\n", " ")