Skip to content

Commit 6ae09f2

Browse files
authored
Fix zsh parse error in pipenv shell command (#6504)
Fixes #6503 The previous implementation used 'declare -f' inside an eval statement for both bash and zsh. However, zsh handles command substitution differently - it expands $() before parsing the function definition, causing a parse error: 'zsh: parse error near }'' This fix separates the zsh and bash cases: - zsh: Uses 'functions -c' to copy function definitions (same approach as fish) - bash: Continues using 'declare -f' which works correctly in bash Also enhanced the test to verify zsh uses 'functions -c' (not 'declare -f') to prevent future regressions.
1 parent ae2fd54 commit 6ae09f2

File tree

2 files changed

+14
-3
lines changed

2 files changed

+14
-3
lines changed

pipenv/shells.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,14 @@ def _get_deactivate_wrapper_script(cmd):
105105
"function deactivate { & $_pipenv_old_deactivate; "
106106
"Remove-Item Env:PIPENV_ACTIVE -ErrorAction SilentlyContinue }"
107107
)
108-
elif cmd.endswith(("bash", "zsh")):
109-
# Bash and zsh support 'declare -f' to copy function definitions
108+
elif cmd.endswith("zsh"):
109+
# Zsh uses 'functions -c' to copy function definitions
110+
return (
111+
"functions -c deactivate _pipenv_old_deactivate; "
112+
"deactivate() { _pipenv_old_deactivate; unset PIPENV_ACTIVE; }"
113+
)
114+
elif cmd.endswith("bash"):
115+
# Bash uses 'declare -f' to copy function definitions
110116
return (
111117
'eval "_pipenv_old_deactivate() { $(declare -f deactivate | tail -n +2) }"; '
112118
"deactivate() { _pipenv_old_deactivate; unset PIPENV_ACTIVE; }"

tests/unit/test_core.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,14 +176,19 @@ def test_load_dot_env_suppresses_message_when_pipenv_active(monkeypatch, capsys,
176176
@pytest.mark.core
177177
def test_deactivate_wrapper_script_includes_unset_pipenv_active():
178178
"""Test that deactivate wrapper scripts include 'unset PIPENV_ACTIVE' or equivalent."""
179-
# Test bash/zsh - should use 'unset PIPENV_ACTIVE'
179+
# Test bash - should use 'declare -f' to copy function and 'unset PIPENV_ACTIVE'
180180
bash_script = _get_deactivate_wrapper_script("bash")
181181
assert "unset PIPENV_ACTIVE" in bash_script
182182
assert "_pipenv_old_deactivate" in bash_script
183+
assert "declare -f" in bash_script
183184

185+
# Test zsh - should use 'functions -c' to copy function (not 'declare -f' which fails in zsh)
186+
# See: https://github.com/pypa/pipenv/issues/6503
184187
zsh_script = _get_deactivate_wrapper_script("zsh")
185188
assert "unset PIPENV_ACTIVE" in zsh_script
186189
assert "_pipenv_old_deactivate" in zsh_script
190+
assert "functions -c" in zsh_script
191+
assert "declare -f" not in zsh_script # zsh doesn't handle this in eval correctly
187192

188193
# Test fish - should use 'set -e PIPENV_ACTIVE'
189194
fish_script = _get_deactivate_wrapper_script("fish")

0 commit comments

Comments
 (0)