Repository: pypa/pipx
Pull request #1347 (2024-04-15 19:50:37)

[pre-commit.ci] pre-commit autoupdate
<!--pre-commit.ci start-->
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.3.5 → v0.3.7](https://github.com/astral-sh/ruff-pre-commit/compare/v0.3.5...v0.3.7)
<!--pre-commit.ci end-->


Patch:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index ed091a6..6a7321b 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -11,7 +11,7 @@ repos:
   hooks:
     - id: pyproject-fmt
 - repo: https://github.com/astral-sh/ruff-pre-commit
-  rev: v0.3.5
+  rev: v0.3.7
   hooks:
   - id: ruff-format
   - id: ruff
diff --git a/changelog.d/1324.bugfix.md b/changelog.d/1324.bugfix.md
new file mode 100644
index 0000000..3312909
--- /dev/null
+++ b/changelog.d/1324.bugfix.md
@@ -0,0 +1,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 cee9df3..c49f2d3 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}")
 


Test patch:
diff --git a/tests/test_reinstall.py b/tests/test_reinstall.py
index 38f013f..b049c2f 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", " ")