pyenv-virtualenv icon indicating copy to clipboard operation
pyenv-virtualenv copied to clipboard

Add `pyenv virtualenv-init` to `.zprofile` instead of `.zshenv`, maybe?

Open levblanc opened this issue 9 years ago • 17 comments

Hi, I am totally new to shell programming and python. I found pyenv and pyenv-virtualenv just because I want to install flask with python 3.4, while my system python version is 2.7. (I am on mac OS X EI Capitan 10.11.6, iTerm2 Build 3.0.10)

After installed both of them on my machine, I followed the instruction and added the following two lines in to my ~/.zshenv:

if which pyenv > /dev/null; then eval "$(pyenv init -)"; fi
if which pyenv-virtualenv-init > /dev/null; then eval "$(pyenv virtualenv-init -)"; fi

Everything worked well when I installed python 3.4.3 with pyenv, so was the pyenv virtualenv creation.

But when I tried to install flask under the folder with the virtual env, pip yelled at me, saying that my current account didn't have permission to access system's python folders, and I could see pip was pointing to the system version of python.

This made me feel like the lines in ~/.zshenv was not working. After many tries on creating new iterm tabs and restarting iterm itself, problem still existed.

Then, under the folder with virtual env created (and set pyenv local), I tried :

$ which python
/usr/bin/python

By comparing to the readme file, this suggests that the shims were not working, right? Then I echo the $PATH, no shims part:

$ echo $PATH
/Users/levblanc/.nvm/versions/node/v4.4.4/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

Then I found this question: .zshenv not sourced on ssh login?

and tried to move the two config lines to .zprofile.

Everything works like magic now. No more permission denied, pip is now pointing to the right place.

PS: I also found answers said the /etc/zprofile file would overwrite .zshenv settings.

I have in following lines in it:

# system-wide environment settings for zsh(1)
if [ -x /usr/libexec/path_helper ]; then
	eval `/usr/libexec/path_helper -s`
fi

and I do have /usr/libexec/path_helper on my machine.

I am confused by all these config files, when and where to put things in ....

--- Want to back this issue? **[Post a bounty on it!](https://www.bountysource.com/issues/38808712-add-pyenv-virtualenv-init-to-zprofile-instead-of-zshenv-maybe?utm_campaign=plugin&utm_content=tracker%2F335155&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F335155&utm_medium=issues&utm_source=github).

levblanc avatar Oct 31 '16 08:10 levblanc

You definitely shouldn't have pyenv in your .zshenv. See http://zsh.sourceforge.net/Doc/Release/Files.html#Files for an explanation of which files are sourced when.

gwerbin avatar Dec 14 '16 22:12 gwerbin

The doc says so (see quote below), that's why I put it into my .zshenv, and that's why I open this issue.

Add pyenv virtualenv-init to your shell to enable auto-activation of virtualenvs. ...... ... Zsh note: Modify your ~/.zshenv file instead of ~/.bash_profile.

But now they are in my .zshprofile and everything works fine. So my thoughts are:

"I am sure .zshprofile is the right place." "But since the doc says so, maybe I did something wrong along the way"

haha

levblanc avatar Dec 15 '16 09:12 levblanc

zprofile/bash_profile is better performance-wise, but you cannot define functions (like pyenv() from pyenv init -) in ~/.zprofile on Linux typically, where no login shell will be used for new terminal instances (but only for the (GUI) login shell).

I am using a mixture of ~/.zprofile (PATH, PYENV_ROOT) and ~/.zshrc myself (custom pyenv function for lazy loading).

pyenv/pyenv-virtualenv's README recommends to use zshenv though indeed: it looks like c6855e0 ("zshenv -> zshrc. update Ubuntu/zsh installation notices") was not merged correctly from rbenv.

See also https://github.com/rbenv/rbenv/wiki/Unix-shell-initialization.

@levblanc So my guess is that either you are running a login shell for every new terminal, or that you are missing the function part(s) of the init procedure (i.e. the precmd function for pyenv-virtualenv).. which is not really necessary for pyenv-virtualenv, but with pyenv you should have a function that can handle the activate|deactivate|rehash|shell commands (by evaling them).

Would you be up for tackling that? :) (i.e. compare the README(s) (pyenv/pyenv-virtualenv) with what rbenv has, and create a PR for pyenv/pyenv-virtualenv)

blueyed avatar Dec 15 '16 10:12 blueyed

For what it's worth I actually have Pyenv in my Zshrc. The modified path gets inherited by subshells and I never seem to have a problem.

That said you could also source your zprofile at the top of your zshrc. That's a standard gimmick in Bash. As far as I can tell, the whole idea of a login vs non-login shell is a little antiquated anyway.

But yes, on OSX all new shells are login shells by default.

gwerbin avatar Dec 15 '16 13:12 gwerbin

For what it's worth I actually have Pyenv in my Zshrc. The modified path gets inherited by subshells and I never seem to have a problem.

I do not expect any problems in this case, but am more considered about overhead. Therefore I lazy-load pyenv only when it is being used for the first time - and only then the version gets displayed in the prompt etc.

That said you could also source your zprofile at the top of your zshrc

Well, what's the point in splitting it then?

That's a standard gimmick in Bash.

No, that's actually required in Bash, not a gimmick - since it will not load the profile for non-login shells.

blueyed avatar Dec 15 '16 13:12 blueyed

@blueyed I am on mac OSX and my shells are login shells. I only have the following lines in my .zprofile, no "function part(s)" :

if which pyenv > /dev/null; then eval "$(pyenv init -)"; fi

if which pyenv-virtualenv-init > /dev/null; then eval "$(pyenv virtualenv-init -)"; fi

I am not sure whether I understand what you meant by evaling those commands (no previous experience in shell programming, sorry), so I tried in my own understanding:

$: eval pyenv activate venv34
>  pyenv-virtualenv: version `venv34' is already activated
$: eval pyenv deactivate venv34
>  (nothing logged, opened new prompt in next line)
$: eval pyenv rehash
>  (nothing logged, opened new prompt in next line)
$: eval pyenv shell venv34
>  (nothing logged, opened new prompt in next line)

Hope these helps.

levblanc avatar Dec 16 '16 07:12 levblanc

I did: echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.zshenv as the README says, and I get this error when opening a new shell:

/home/akronix/.zshenv:1: command not found: pyenv

However, adding it to zshrc it does work: echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.zshrc

Akronix avatar Dec 06 '18 21:12 Akronix

@Akronix that's because your PATH probably isn't set in Zshenv. As I mentioned, I strongly do not recommend initializing Pyenv in Zshenv. Zshrc is the correct location, from the perspective of intended Zsh semantics.

gwerbin avatar Dec 06 '18 21:12 gwerbin

@Akronix that's because your PATH probably isn't set in Zshenv. As I mentioned, I strongly do not recommend initializing Pyenv in Zshenv. Zshrc is the correct location, from the perspective of intended Zsh semantics.

The README of the repo should be updated then.

Akronix avatar Dec 06 '18 21:12 Akronix

I had the same issue and tried to solve it without moving the code around. But appeared .zshenv is not a proper place even if I define PATH variable properly. It is still evaling everything but the python version is system's one.

Please update README to properly support ZSH as a lot of users use this shell.

sshishov avatar May 16 '19 09:05 sshishov

I guess PRs are welcome, but there might be some even already. Also see my comment from 2016: https://github.com/pyenv/pyenv-virtualenv/issues/192#issuecomment-267298104 In general you do not need pyenv-virtualenv even, you know? :)

blueyed avatar May 16 '19 11:05 blueyed

@blueyed there's been a PR to modify the README to use .zshrc instead of . zshenv, but it was closed https://github.com/pyenv/pyenv-virtualenv/pull/167 perhaps it can be reopened?

tekumara avatar May 19 '19 05:05 tekumara

In general you do not need pyenv-virtualenv even, you know? :)

Don't I? what do you use then @blueyed ?

Akronix avatar Jun 08 '19 21:06 Akronix

@Akronix I am using pyenv to install/manage different Python version, but https://github.com/Tarrasch/zsh-autoenv then to activate virtualenvs for different projects (which I typically install using python -m venv .venv there, and zsh-autoenv (or other tools) then activate it automatically; zsh-autoenv has a recipe, but requires Zsh obviously). You can also use e.g. ´~/.pyenv/versions/…/bin/python -m venv .venv` directly instead of going through (installed/activated) pyenv obviously. From my experience pyenv/pyenv-virtualenv's shell installation adds quite some overhead to startup by default, and is often not needed. That's also why I am reluctant to just stash it into zshrc, if zprofile typically is enough (but it depends on your setup etc).

blueyed avatar Jun 09 '19 09:06 blueyed

As for this issue: I see that .zshenv is used in the readme, and it appears to work for the author (#167).

If you get errors due to pyenv not being found this could mean that e.g. you're installing pyenv then only (later) in your zshrc or similar, for example.

blueyed avatar Jun 09 '19 09:06 blueyed

@Akronix I am using pyenv to install/manage different Python version, but https://github.com/Tarrasch/zsh-autoenv then to activate virtualenvs for different projects (which I typically install using python -m venv .venv there, and zsh-autoenv (or other tools) then activate it automatically; zsh-autoenv has a recipe, but requires Zsh obviously). You can also use e.g. ´~/.pyenv/versions/…/bin/python -m venv .venv` directly instead of going through (installed/activated) pyenv obviously. From my experience pyenv/pyenv-virtualenv's shell installation adds quite some overhead to startup by default, and is often not needed. That's also why I am reluctant to just stash it into zshrc, if zprofile typically is enough (but it depends on your setup etc).

@blueyed While it's true that I've noticed some overhead when using pyenv, I find it more comfortable than having to write text files which, although they are very powerful, they'll be just for activating a virtualenv. I've used smartcd in the past and I find pyenv way more convenient.

Akronix avatar Jul 09 '19 14:07 Akronix

I am here searching for a simple answer like everyone else. Buyer beware, but this is what appears to work for me:

.zshrc:

if command -v pyenv 1>/dev/null 2>&1; then
  eval "$(pyenv init -)"
fi

setopt interactive_comments

sh ~/PythonStatus.sh

.zprofile:

export PATH="/usr/local/opt/python/libexec/bin:$PATH"

Finally, because I am tired of guessing what's where, PythonStatus.sh:

#!/bin/bash -x

echo ""
echo "StatusOfPthon here"
echo ""
echo "pyenv version: "
pyenv --version
echo ""
echo "pyenv global: "
pyenv global
echo ""
echo "pyenv version-name: "
pyenv version-name
echo ""
echo "virtualenv version-name: "
virtualenv --version
echo ""
echo "python: "
python --version
echo ""

Hope that helps, or at least doesn't hurt...

valhuber avatar Nov 01 '20 15:11 valhuber

The current README suggests putting the init line to .zshrc. So this is probably no longer relevant.

native-api avatar Jan 31 '23 21:01 native-api