Prezto: Python module failing to run pyenv virtualenv-init

Created on 16 Aug 2017  路  16Comments  路  Source: sorin-ionescu/prezto

Description

It seems like the Python module is incorrectly using the commands array, by trying to find a command named pyenv-virtualenv-init, causing the module to not find and run pyenv virtualenv-init.
Line in question: https://github.com/sorin-ionescu/prezto/blob/master/modules/python/init.zsh#L96

But looking at the code history, the Python module has been using this since April of 2017 1050a0a290324f3b96256d3b1fefe4a84ab402d0, so I feel like I must be doing something wrong.

I have pyenv installed with the virtualenv plugin, but when I run $+commands[pyenv-virtualenv-init] in my shell I get 0

Expected behavior

virtualenv is loaded via pyenv

Actual behavior

virtualenv is not loaded, and an error is printed on shell open

/home/zwhaley/.zprezto/modules/python/init.zsh:source:109: no such file or directory: 

Steps to Reproduce

  1. Enable Python module zstyle ':prezto:module:python:virtualenv' auto-switch 'yes'
  2. Open shell

Versions

  • Prezto commit: dbf96d2d3749b2905927a08c55a8c9eba12c8425
  • ZSH version: zsh 5.3.1 (x86_64-redhat-linux-gnu)
  • OS information: Fedora release 26 (Twenty Six) x86_64

Most helpful comment

@indrajitr The reason it worked for me is because I was on a Mac and installed the pyenv-virtualenv package from Homebrew. This package places an executable pyenv-virtualenv-init in /usr/local/bin, which is on the user's path, so the $+commands[pyenv-virtualenv-init] returns true.

However, when installing pyenv-virtualenv on Ubuntu using either the pyenv-installer or simply Git cloning into ~/.pyenv/plugins, there is no pyenv-virtualenv-init on the path. @zachwhaley's grep solution works in either case, so I think that is the way to go.

Edit: There does seem to be some confusion here regarding the difference between pyenv-virtualenv-init and pyenv virtualenv-init. One has a dash, the other a space. The former is what prezto is currently checking for on the path, while the latter is the actual command to be executed.

All 16 comments

Additionally, if one installs pyenv and pyenv-virtualenv via Homebrew, the condition (( $+VIRTUALENVWRAPPER_VIRTUALENV || $+commands[virtualenv] )) in the if-check will return false, since neither the environment variable or the command is defined. This prevents the execution from even reaching the if (( $+commands[pyenv-virtualenv-init] )); then line.

I think the first if-check condition should be changed to

(( $+VIRTUALENVWRAPPER_VIRTUALENV || $+commands[virtualenv] || $+commands[pyenv-virtualenv-init] ))

Doing some more diving, and it seems like there is a pyenv-virtualenv-init executable in $(pyenv root)/plugins/pyenv-virtualenv/bin/. Is this something Prezto is supposed to add to my path for me?

@zachwhaley How did you install pyenv-virtualenv?

@gpanders I believe I installed it using pyenv-installer

@zachwhaley I removed my last comment. I just looked through the pyenv source and found this line:

for plugin_bin in "${PYENV_ROOT}/plugins/"*/bin; do
    PATH="${plugin_bin}:${PATH}"
done

So if the pyenv-virtualenv-init executable is truly in your $(pyenv root)/plugins/pyenv-virtualenv/bin/ directory as you claim, it should be added to your path automatically with the execution of eval $(pyenv init -). It seems like something else is afoot here.

@gpanders Good question. I'll look into this and get back to y'all.

So running eval "$(pyenv init -)" does not add any plugin bin paths to _my_ shell session's PATH, but instead adds to the sub-shell session that is run when pyenv is called.

pyenv init - itself just prints out some shell commands that we then eval, which is what is actually added to _my_ shell session. And from the looks of it, the only thing that is added to the user's path is $HOME/.pyenv/shims

So I do think your original comment was correct. Prezto can't rely on the plugin executables being in the user's PATH.

SO link :slightly_smiling_face:

If we can't rely on pyenv being in the path, how can we find it?

virtualenvwrapper is reasonable because it has a few possible names it can be called (some of which are in the PATH and some which aren't)... but people don't generally install it to some random location. Are there common locations the pyenv commands are installed which we could check (allowing an override for completely different paths)?

I personally don't currently use pyenv... I stick to just virtualenvwrapper... but I would be happy to review any pull requests which attempt to solve this.

@belak pyenv _is_ on the path, but pyenv-virtualenv-init is not for certain installation methods (i.e. using Github to clone the project, which is what one would do on Ubuntu).

The command pyenv virtualenv-init - is valid (notice the space between pyenv and virtualenv-init. This is a different command) and is what needs to be executed, so we could just call that and check the return code for a zero value; however, I don't know what the performance impact is of executing that function simply for an if condition. I'll bet there is a more elegant way.

@zachwhaley did you experienced this problem with pyenv virtualenvwrapper?
https://github.com/pyenv/pyenv-virtualenvwrapper/issues/19

or something similar to it?

If you want to avoid calling a command that doesn't exist, you could use the pyenv commands command to list the available commands and grep for virtualenv-init

e.g.

if pyenv commands | command grep -q virtualenv-init; then
    $(pyenv virtualenv-init -)
fi

@diraol I don't have virtualenvwrapper installed, which is why the fallback in python/init.zsh doesn't work for me.

@zachwhaley That looks like it should work to me. Do you want to test it and write a PR?

@gpanders Sure!

Okay, catching up on this one. Apologies for delayed response.

If you want to avoid calling a command that doesn't exist, you could use the pyenv commands command to list the available commands and grep for virtualenv-init

e.g.

if pyenv commands | command grep -q virtualenv-init; then
    $(pyenv virtualenv-init -)
fi

Based on source, it seems to be doing regular $PATH scanning.

But seems like this worked for @gpanders, so I am wondering how this is getting treated different from $+commands[pyenv-virtualenv-init].


Edit: Is it possible that $HOME/.pyenv/shims has been prepended to the $PATH as a result of a pyenv init - in _~/.zshrc_?

@indrajitr The reason it worked for me is because I was on a Mac and installed the pyenv-virtualenv package from Homebrew. This package places an executable pyenv-virtualenv-init in /usr/local/bin, which is on the user's path, so the $+commands[pyenv-virtualenv-init] returns true.

However, when installing pyenv-virtualenv on Ubuntu using either the pyenv-installer or simply Git cloning into ~/.pyenv/plugins, there is no pyenv-virtualenv-init on the path. @zachwhaley's grep solution works in either case, so I think that is the way to go.

Edit: There does seem to be some confusion here regarding the difference between pyenv-virtualenv-init and pyenv virtualenv-init. One has a dash, the other a space. The former is what prezto is currently checking for on the path, while the latter is the actual command to be executed.

Was this page helpful?
0 / 5 - 0 ratings