Repository: pypa/pipx
Pull request #1397 (2024-05-11 13:30:52)

Move --global option into shared parser
<!-- add an 'x' in the brackets below -->

- [x] I have added a news fragment under `changelog.d/` (if the patch affects the end users)

## Summary of changes
Move `--global` option into shared parser, such that it can be passed after the subcommand, for example `pipx ensurepath --global`.


## Test plan

<!-- provide evidence of testing, preferably with command(s) that can be copy+pasted by others -->

Tested by running

```
pipx install --global nox
pipx ensurepath --global
```



Patch:
diff --git a/changelog.d/1397.bugfix.md b/changelog.d/1397.bugfix.md
new file mode 100644
index 0000000..9f68ee7
--- /dev/null
+++ b/changelog.d/1397.bugfix.md
@@ -0,0 +1,1 @@
+Move `--global` option into shared parser, such that it can be passed after the subcommand, for example `pipx ensurepath --global`.
diff --git a/src/pipx/main.py b/src/pipx/main.py
index 60f6145..de2b74d 100644
--- a/src/pipx/main.py
+++ b/src/pipx/main.py
@@ -877,6 +877,14 @@ def get_command_parser() -> Tuple[argparse.ArgumentParser, Dict[str, argparse.Ar
         ),
     )
 
+    if not constants.WINDOWS:
+        shared_parser.add_argument(
+            "--global",
+            action="store_true",
+            dest="is_global",
+            help="Perform action globally for all users.",
+        )
+
     parser = argparse.ArgumentParser(
         prog=prog_name(),
         formatter_class=LineWrapRawTextHelpFormatter,
@@ -906,13 +914,6 @@ def get_command_parser() -> Tuple[argparse.ArgumentParser, Dict[str, argparse.Ar
     _add_ensurepath(subparsers, shared_parser)
     _add_environment(subparsers, shared_parser)
 
-    if not constants.WINDOWS:
-        parser.add_argument(
-            "--global",
-            action="store_true",
-            dest="is_global",
-            help="Perform action globally for all users.",
-        )
     parser.add_argument("--version", action="store_true", help="Print version and exit")
     subparsers.add_parser(
         "completions",


Test patch:
diff --git a/tests/test_environment.py b/tests/test_environment.py
index ae1a8d8..bfd91c5 100644
--- a/tests/test_environment.py
+++ b/tests/test_environment.py
@@ -51,7 +51,7 @@ def test_resolve_user_dir_in_env_paths(monkeypatch):
 
 @skip_if_windows
 def test_cli_global(pipx_temp_env, monkeypatch, capsys):
-    assert not run_pipx_cli(["--global", "environment"])
+    assert not run_pipx_cli(["environment", "--global"])
     captured = capsys.readouterr()
     assert fnmatch.fnmatch(captured.out, "*PIPX_HOME=*global/pipxhome*")
     assert fnmatch.fnmatch(captured.out, "*PIPX_BIN_DIR=*global_otherdir/pipxbindir*")
diff --git a/tests/test_inject.py b/tests/test_inject.py
index fb2d177..e60e4d9 100644
--- a/tests/test_inject.py
+++ b/tests/test_inject.py
@@ -11,8 +11,8 @@ def test_inject_simple(pipx_temp_env, capsys):
 
 @skip_if_windows
 def test_inject_simple_global(pipx_temp_env, capsys):
-    assert not run_pipx_cli(["--global", "install", "pycowsay"])
-    assert not run_pipx_cli(["--global", "inject", "pycowsay", PKG["black"]["spec"]])
+    assert not run_pipx_cli(["install", "--global", "pycowsay"])
+    assert not run_pipx_cli(["inject", "--global", "pycowsay", PKG["black"]["spec"]])
 
 
 @pytest.mark.parametrize("metadata_version", PIPX_METADATA_LEGACY_VERSIONS)
diff --git a/tests/test_list.py b/tests/test_list.py
index 7b65e89..1e0c6fc 100644
--- a/tests/test_list.py
+++ b/tests/test_list.py
@@ -34,7 +34,7 @@ def test_cli_global(pipx_temp_env, monkeypatch, capsys):
     captured = capsys.readouterr()
     assert "installed package" in captured.out
 
-    assert not run_pipx_cli(["--global", "list"])
+    assert not run_pipx_cli(["list", "--global"])
     captured = capsys.readouterr()
     assert "nothing has been installed with pipx" in captured.err
 
diff --git a/tests/test_reinstall.py b/tests/test_reinstall.py
index f59095b..175918a 100644
--- a/tests/test_reinstall.py
+++ b/tests/test_reinstall.py
@@ -12,8 +12,8 @@ def test_reinstall(pipx_temp_env, capsys):
 
 @skip_if_windows
 def test_reinstall_global(pipx_temp_env, capsys):
-    assert not run_pipx_cli(["--global", "install", "pycowsay"])
-    assert not run_pipx_cli(["--global", "reinstall", "--python", sys.executable, "pycowsay"])
+    assert not run_pipx_cli(["install", "--global", "pycowsay"])
+    assert not run_pipx_cli(["reinstall", "--global", "--python", sys.executable, "pycowsay"])
 
 
 def test_reinstall_nonexistent(pipx_temp_env, capsys):
diff --git a/tests/test_runpip.py b/tests/test_runpip.py
index 801bbdc..4f36e34 100644
--- a/tests/test_runpip.py
+++ b/tests/test_runpip.py
@@ -8,5 +8,5 @@ def test_runpip(pipx_temp_env, monkeypatch, capsys):
 
 @skip_if_windows
 def test_runpip_global(pipx_temp_env, monkeypatch, capsys):
-    assert not run_pipx_cli(["--global", "install", "pycowsay"])
-    assert not run_pipx_cli(["--global", "runpip", "pycowsay", "list"])
+    assert not run_pipx_cli(["install", "--global", "pycowsay"])
+    assert not run_pipx_cli(["runpip", "--global", "pycowsay", "list"])
diff --git a/tests/test_uninject.py b/tests/test_uninject.py
index 054d266..a785a4c 100644
--- a/tests/test_uninject.py
+++ b/tests/test_uninject.py
@@ -15,12 +15,12 @@ def test_uninject_simple(pipx_temp_env, capsys):
 
 @skip_if_windows
 def test_uninject_simple_global(pipx_temp_env, capsys):
-    assert not run_pipx_cli(["--global", "install", "pycowsay"])
-    assert not run_pipx_cli(["--global", "inject", "pycowsay", PKG["black"]["spec"]])
-    assert not run_pipx_cli(["--global", "uninject", "pycowsay", "black"])
+    assert not run_pipx_cli(["install", "--global", "pycowsay"])
+    assert not run_pipx_cli(["inject", "--global", "pycowsay", PKG["black"]["spec"]])
+    assert not run_pipx_cli(["uninject", "--global", "pycowsay", "black"])
     captured = capsys.readouterr()
     assert "Uninjected package black" in captured.out
-    assert not run_pipx_cli(["--global", "list", "--include-injected"])
+    assert not run_pipx_cli(["list", "--global", "--include-injected"])
     captured = capsys.readouterr()
     assert "black" not in captured.out
 
diff --git a/tests/test_uninstall.py b/tests/test_uninstall.py
index 9bf9360..236dcca 100644
--- a/tests/test_uninstall.py
+++ b/tests/test_uninstall.py
@@ -31,8 +31,8 @@ def test_uninstall(pipx_temp_env):
 
 @skip_if_windows
 def test_uninstall_global(pipx_temp_env):
-    assert not run_pipx_cli(["--global", "install", "pycowsay"])
-    assert not run_pipx_cli(["--global", "uninstall", "pycowsay"])
+    assert not run_pipx_cli(["install", "--global", "pycowsay"])
+    assert not run_pipx_cli(["uninstall", "--global", "pycowsay"])
 
 
 def test_uninstall_circular_deps(pipx_temp_env):
diff --git a/tests/test_upgrade.py b/tests/test_upgrade.py
index d5fa0bf..54c18f5 100644
--- a/tests/test_upgrade.py
+++ b/tests/test_upgrade.py
@@ -20,15 +20,15 @@ def test_upgrade(pipx_temp_env, capsys):
 
 @skip_if_windows
 def test_upgrade_global(pipx_temp_env, capsys):
-    assert run_pipx_cli(["--global", "upgrade", "pycowsay"])
+    assert run_pipx_cli(["upgrade", "--global", "pycowsay"])
     captured = capsys.readouterr()
     assert "Package is not installed" in captured.err
 
-    assert not run_pipx_cli(["--global", "install", "pycowsay"])
+    assert not run_pipx_cli(["install", "--global", "pycowsay"])
     captured = capsys.readouterr()
     assert "installed package pycowsay" in captured.out
 
-    assert not run_pipx_cli(["--global", "upgrade", "pycowsay"])
+    assert not run_pipx_cli(["upgrade", "--global", "pycowsay"])
     captured = capsys.readouterr()
     assert "pycowsay is already at latest version" in captured.out