Skip to content

Commit

Permalink
Merge branch 'main' into allow_spaces_in_home_via_envvar
Browse files Browse the repository at this point in the history
  • Loading branch information
Gitznik authored Jun 21, 2024
2 parents 8d9ac27 + 786eb99 commit 018af10
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 11 deletions.
1 change: 1 addition & 0 deletions changelog.d/1451.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a `--prepend` option to the `pipx ensurepath` command to allow prepending `pipx`'s location to `PATH` rather than appending to it. This is useful when you want to prioritize `pipx`'s executables over other executables in your `PATH`.
44 changes: 39 additions & 5 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,23 @@ pipx works on macOS, linux, and Windows.
```
brew install pipx
pipx ensurepath
sudo pipx ensurepath --global # optional to allow pipx actions in global scope. See "Global installation" section below.
```

#### Additional (optional) commands

To allow pipx actions in global scope.
```
sudo pipx ensurepath --global
```

To prepend the pipx bin directory to PATH instead of appending it.

```
sudo pipx ensurepath --prepend
```

For more details, refer to [Customising your installation](#customising-your-installation).

### On Linux:

- Ubuntu 23.04 or above
Expand All @@ -30,25 +44,37 @@ sudo pipx ensurepath --global # optional to allow pipx actions in global scope.
sudo apt update
sudo apt install pipx
pipx ensurepath
sudo pipx ensurepath --global # optional to allow pipx actions in global scope. See "Global installation" section below.
```

- Fedora:

```
sudo dnf install pipx
pipx ensurepath
sudo pipx ensurepath --global # optional to allow pipx actions in global scope. See "Global installation" section below.
```

- Using `pip` on other distributions:

```
python3 -m pip install --user pipx
python3 -m pipx ensurepath
sudo pipx ensurepath --global # optional to allow pipx actions in global scope. See "Global installation" section below.
```

#### Additional (optional) commands

To allow pipx actions in global scope.

```
sudo pipx ensurepath --global
```

To prepend the pipx bin directory to PATH instead of appending it.

```
sudo pipx ensurepath --prepend
```

For more details, refer to [Customising your installation](#customising-your-installation).

### On Windows:

Expand Down Expand Up @@ -160,7 +186,9 @@ sudo PIPX_HOME=/opt/pipx PIPX_BIN_DIR=/usr/local/bin PIPX_MAN_DIR=/usr/local/sha
> This was reverted in 1.5.0 for Windows and MacOS. We heavily recommend not using these locations on Windows and MacOS anymore, due to
> multiple incompatibilities discovered with these locations, documented [here](https://github.com/pypa/pipx/discussions/1247#discussion-6188916).

### Global installation
### Customising your installation

#### `--global` argument

Pipx also comes with a `--global` argument which helps to execute actions in global scope which exposes the app to
all system users. By default the global binary location is set to `/usr/local/bin` and can be overridden with the
Expand All @@ -171,6 +199,12 @@ if you intend to use this feature.

Note that the `--global` argument is not supported on Windows.

#### `--prepend` argument

The `--prepend` argument can be passed to the `pipx ensurepath` command to prepend the `pipx` bin directory to the user's PATH
environment variable instead of appending to it. This can be useful if you want to prioritise `pipx`-installed binaries over
system-installed binaries of the same name.

## Upgrade pipx

On macOS:
Expand Down
16 changes: 11 additions & 5 deletions src/pipx/commands/ensure_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ def get_pipx_user_bin_path() -> Optional[Path]:
return pipx_bin_path


def ensure_path(location: Path, *, force: bool) -> Tuple[bool, bool]:
def ensure_path(location: Path, *, force: bool, prepend: bool = False) -> Tuple[bool, bool]:
"""Ensure location is in user's PATH or add it to PATH.
If prepend is True, location will be prepended to PATH, else appended.
Returns True if location was added to PATH
"""
location_str = str(location)
Expand All @@ -61,7 +62,10 @@ def ensure_path(location: Path, *, force: bool) -> Tuple[bool, bool]:
in_current_path = userpath.in_current_path(location_str)

if force or (not in_current_path and not need_shell_restart):
path_added = userpath.append(location_str, "pipx")
if prepend:
path_added = userpath.prepend(location_str, "pipx")
else:
path_added = userpath.append(location_str, "pipx")
if not path_added:
print(
pipx_wrap(
Expand Down Expand Up @@ -96,7 +100,7 @@ def ensure_path(location: Path, *, force: bool) -> Tuple[bool, bool]:
return (path_added, need_shell_restart)


def ensure_pipx_paths(force: bool) -> ExitCode:
def ensure_pipx_paths(force: bool, prepend: bool = False) -> ExitCode:
"""Returns pipx exit code."""
bin_paths = {paths.ctx.bin_dir}

Expand All @@ -106,8 +110,10 @@ def ensure_pipx_paths(force: bool) -> ExitCode:

path_added = False
need_shell_restart = False
path_action_str = "prepended to" if prepend else "appended to"

for bin_path in bin_paths:
(path_added_current, need_shell_restart_current) = ensure_path(bin_path, force=force)
(path_added_current, need_shell_restart_current) = ensure_path(bin_path, prepend=prepend, force=force)
path_added |= path_added_current
need_shell_restart |= need_shell_restart_current

Expand All @@ -128,7 +134,7 @@ def ensure_pipx_paths(force: bool) -> ExitCode:
logger.warning(
pipx_wrap(
f"""
{hazard} All pipx binary directories have been added to PATH. If you
{hazard} All pipx binary directories have been {path_action_str} PATH. If you
are sure you want to proceed, try again with the '--force'
flag.
"""
Expand Down
10 changes: 9 additions & 1 deletion src/pipx/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ def run_pipx_command(args: argparse.Namespace, subparsers: Dict[str, argparse.Ar
return commands.run_pip(package, venv_dir, args.pipargs, args.verbose)
elif args.command == "ensurepath":
try:
return commands.ensure_pipx_paths(force=args.force)
return commands.ensure_pipx_paths(prepend=args.prepend, force=args.force)
except Exception as e:
logger.debug("Uncaught Exception:", exc_info=True)
raise PipxError(str(e), wrap_message=False) from None
Expand Down Expand Up @@ -875,6 +875,14 @@ def _add_ensurepath(subparsers: argparse._SubParsersAction, shared_parser: argpa
),
parents=[shared_parser],
)
p.add_argument(
"--prepend",
action="store_true",
help=(
"Prepend directories to your PATH instead of appending. "
"This is useful if you want to prioritize pipx apps over system apps."
),
)
p.add_argument(
"--force",
"-f",
Expand Down

0 comments on commit 018af10

Please sign in to comment.