diff --git a/README.md b/README.md index ade2f4cf9..5abd4f0e1 100644 --- a/README.md +++ b/README.md @@ -129,22 +129,35 @@ For command reference, see [Commands](https://pipenv.pypa.io/en/latest/commands/ ### Shell Completion -To enable completion in fish, add this to your configuration `~/.config/fish/completions/pipenv.fish`: +Shell completion is powered by [argcomplete](https://kislyuk.github.io/argcomplete/). +Install the optional dependency first: - eval (env _PIPENV_COMPLETE=fish_source pipenv) + pip install "pipenv[completion]" + +For **fish**, add this to `~/.config/fish/completions/pipenv.fish`: + + register-python-argcomplete --shell fish pipenv | source There is also a [fish plugin](https://github.com/fisherman/pipenv), which will automatically activate your subshells for you! -Alternatively, with zsh, add this to your configuration `~/.zshrc`: +For **zsh**, add this to your `~/.zshrc`: + + autoload -U bashcompinit + bashcompinit + eval "$(register-python-argcomplete pipenv)" - eval "$(_PIPENV_COMPLETE=zsh_source pipenv)" +For **bash** (including Git Bash on Windows), add this to `~/.bashrc` or `~/.bash_profile`: -Alternatively, with bash, add this to your configuration `~/.bashrc` or `~/.bash_profile`: + eval "$(register-python-argcomplete pipenv)" - eval "$(_PIPENV_COMPLETE=bash_source pipenv)" +Then reload your shell, and tab completions are enabled! -Magic shell completions are now enabled! +> **Note:** If you are upgrading from pipenv < 2026.5.0, the old +> `_PIPENV_COMPLETE` environment variable method no longer works. +> Replace it with the `register-python-argcomplete` commands above. +> See the [Shell Completion docs](https://pipenv.pypa.io/en/latest/shell.html#shell-completion) +> for details. Usage ------- diff --git a/docs/shell.md b/docs/shell.md index 5ffd0bc14..602f3cb68 100644 --- a/docs/shell.md +++ b/docs/shell.md @@ -204,6 +204,35 @@ After reloading your shell, type `pipenv ` and press `Tab` — you should see th list of available subcommands. Pressing `Tab` again after a partial subcommand name (e.g. `pipenv ins`) completes it to `pipenv install`. +#### Git Bash (Windows) + +Git Bash supports bash completion. Add to your `~/.bashrc` (typically +`C:\Users\\.bashrc`): + +```bash +eval "$(register-python-argcomplete pipenv)" +``` + +Then restart Git Bash or run `source ~/.bashrc`. + +### Migrating from pipenv < 2026.5.0 + +In older versions of pipenv (before 2026.5.0), shell completion was powered by +Click and activated with the `_PIPENV_COMPLETE` environment variable: + +```bash +# OLD method — no longer works in pipenv >= 2026.5.0 +eval "$(_PIPENV_COMPLETE=bash_source pipenv)" # bash +eval "$(_PIPENV_COMPLETE=zsh_source pipenv)" # zsh +_PIPENV_COMPLETE=fish_source pipenv | source # fish +``` + +Starting with pipenv 2026.5.0, shell completion uses +[argcomplete](https://kislyuk.github.io/argcomplete/) instead. **Replace** the +lines above with the `register-python-argcomplete` commands shown in the +[Activation](#activation) section and make sure the `argcomplete` package is +installed (`pip install "pipenv[completion]"`). + ### Troubleshooting If completion is not working: @@ -225,6 +254,10 @@ If completion is not working: ``` It should print a shell function definition without errors. +5. **If you see a migration message** about `_PIPENV_COMPLETE`, you are using + the old activation method. See [Migrating from pipenv < 2026.5.0](#migrating-from-pipenv--202650) + above. + ## Best Practices for Shell Configuration ### Proper PATH Configuration diff --git a/pipenv/cli/command.py b/pipenv/cli/command.py index 13b4fd243..75ab7f693 100644 --- a/pipenv/cli/command.py +++ b/pipenv/cli/command.py @@ -627,6 +627,23 @@ def cli(): from pipenv.utils.shell import system_which from pipenv.utils.virtualenv import do_where, warn_in_virtualenv + # Handle legacy _PIPENV_COMPLETE env var from the Click-based CLI. + # Since pipenv 2026.5.0, shell completion uses argcomplete instead. + # Detect the old mechanism and provide a helpful migration message. + if os.environ.get("_PIPENV_COMPLETE"): + print( + "Shell completion has changed in pipenv >= 2026.5.0.\n" + "The _PIPENV_COMPLETE environment variable is no longer supported.\n" + "\n" + "To enable shell completion, install the completion extra and use:\n" + " pip install pipenv[completion]\n" + ' eval "$(register-python-argcomplete pipenv)"\n' + "\n" + "For more details, see: https://pipenv.pypa.io/en/latest/shell.html#shell-completion", + file=sys.stderr, + ) + sys.exit(1) + parser = build_parser() # Enable shell completion when argcomplete is installed. diff --git a/pipenv/routines/audit.py b/pipenv/routines/audit.py index 781d3c20a..6e4d71fd3 100644 --- a/pipenv/routines/audit.py +++ b/pipenv/routines/audit.py @@ -9,6 +9,7 @@ import logging import subprocess import sys +import tempfile from pipenv.utils import console, err from pipenv.utils.processes import run_command @@ -115,9 +116,9 @@ def build_audit_options( if aliases: options.append("--aliases") - # Use lockfile (pyproject.toml / pylock.toml) - if use_lockfile: - options.append("--locked") + # Note: use_lockfile is handled in do_audit by generating a temporary + # requirements file from Pipfile.lock, since pip-audit's --locked flag + # does not support Pipfile.lock format. # Requirements file if requirements_file: @@ -165,7 +166,7 @@ def do_audit( # noqa: PLR0913 Supports auditing from: - The current virtualenv (default) - - pyproject.toml / pylock.toml files (with --locked flag) + - Pipfile.lock (with --locked flag, converted to requirements format for pip-audit) """ if not verbose: logging.getLogger("pipenv").setLevel(logging.ERROR if quiet else logging.WARN) @@ -222,9 +223,35 @@ def do_audit( # noqa: PLR0913 python_path = project_python(project, system=system) cmd = [python_path, "-m", "pip_audit"] + options - # If using lockfile mode, add the project directory path + # If using lockfile mode, generate a temporary requirements file from + # Pipfile.lock and pass it via -r. pip-audit's own --locked flag only + # recognises pylock.toml / poetry.lock / uv.lock — not Pipfile.lock. + tmp_requirements = None if use_lockfile: - cmd.append(project.project_directory) + if not project.lockfile_exists: + err.print( + "[red]Pipfile.lock not found. Run 'pipenv lock' first.[/red]" + ) + sys.exit(1) + + from pipenv.utils.requirements import requirements_from_lockfile + + lockfile = project.load_lockfile(expand_env_vars=False) + deps = {} + deps.update(lockfile.get("default", {})) + deps.update(lockfile.get("develop", {})) + + lines = requirements_from_lockfile( + deps, include_hashes=False, include_markers=True + ) + + tmp_requirements = tempfile.NamedTemporaryFile( + mode="w", suffix=".txt", prefix="pipenv-audit-", delete=False + ) + tmp_requirements.write("\n".join(lines)) + tmp_requirements.flush() + tmp_requirements.close() + cmd.extend(["-r", tmp_requirements.name]) if not quiet and not project.s.is_quiet() and verbose: console.print(f"[dim]Running: {' '.join(cmd)}[/dim]") @@ -240,3 +267,8 @@ def do_audit( # noqa: PLR0913 except Exception as e: err.print(f"[red]Error running pip-audit: {str(e)}[/red]") sys.exit(1) + finally: + if tmp_requirements is not None: + import os + + os.unlink(tmp_requirements.name)