pyenv - environment "activated", but python and pip not found

Viewed 2444

I suppose there is something wrong with my bash init scripts (like .bashrc or .bash_profile). But let's start from beginning.

I can create and activate pyenv environment, but when I try to use python, I get error: -bash: python: command not found. It looks like pyenv understands creation and swapping envorinments. I mean, it's probably not malformed. There is preview of my tries:

$ mkdir test-python-project
$ cd test-python-project/
$ pyenv versions
* system (set by /home/vagrant/.pyenv/version)
  3.7.10
  3.7.10/envs/k-pkb-env
$ pyenv virtualenv 3.7.10 test-env
Looking in links: /tmp/tmpkwojcc1e
Requirement already satisfied: setuptools in /home/vagrant/.pyenv/versions/3.7.10/envs/test-env/lib/python3.7/site-packages (47.1.0)
Requirement already satisfied: pip in /home/vagrant/.pyenv/versions/3.7.10/envs/test-env/lib/python3.7/site-packages (20.1.1)
$ pyenv activate test-env
pyenv-virtualenv: prompt changing will be removed from future release. configure export PYENV_VIRTUALENV_DISABLE_PROMPT=1 to simulate the behavior.
(test-env) $ python
-bash: python: command not found
(test-env) $ pyenv local test-env
(test-env) $ cd ..
(test-env) $ pyenv deactivate
$ cd test-python-project/
(test-env) $ python
-bash: python: command not found
(test-env) $ pip
-bash: pip: command not found
(test-env) $ pyenv version
test-env (set by /home/vagrant/Work/test-python-project/.python-version)

I'm not sure how to configure bash init scripts, because in pyenv readme they suggest using .profile, which I don't have.

So, there are my bash inits:

.bashrc

$ cat .bashrc
# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

# User specific environment
if ! [[ "$PATH" =~ "$HOME/.local/bin:$HOME/bin:" ]]
then
    PATH="$HOME/.local/bin:$HOME/bin:$PATH"
fi
export PATH

# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=

# User specific aliases and functions

.bash_profile

$ cat .bash_profile
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# User specific environment and startup programs

# PyEnv
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

Some additional information:

$PATH variable

$ echo $PATH
/home/vagrant/.pyenv/plugins/pyenv-virtualenv/shims:/home/vagrant/.pyenv/bin:/home/vagrant/.local/bin:/home/vagrant/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin

It's a bit strange for me, because this additional paths added by pyenv doesn't seem to contain path to desired virtual environment:

$ ls /home/vagrant/.pyenv/plugins/pyenv-virtualenv/shims
activate  deactivate
$ ls /home/vagrant/.pyenv/bin
pyenv

type python

$ type python
-bash: type: python: not found

which python

$ which python
/usr/bin/which: no python in (/home/vagrant/.pyenv/plugins/pyenv-virtualenv/shims:/home/vagrant/.pyenv/bin:/home/vagrant/.local/bin:/home/vagrant/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin)

I tried also pyenv rehash, but also still no effect:

(test-env) [vagrant@centos test-python-project]$ pyenv rehash
(test-env) [vagrant@centos test-python-project]$ python
-bash: python: command not found

2 Answers

With some help from @Simba, I managed to have my configuration correct:

.bash_profile

# .bash_profile

# !!! ITS IMPORTANT THESE LINES MUST BE BEFORE . ~/.bashrc
# PyEnv - only path-related
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
# !!! ITS IMPORTANT THESE LINES ABOVE MUST BE BEFORE . ~/.bashrc



# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# User specific environment and startup programs

.bashrc

# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

# User specific environment
if ! [[ "$PATH" =~ "$HOME/.local/bin:$HOME/bin:" ]]
then
    PATH="$HOME/.local/bin:$HOME/bin:$PATH"
fi
export PATH

# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=

# User specific aliases and functions

# PyEnv - commands
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

Solution

READ THE PYENV GUIDE CAREFULLY.

You didn't follow pyenv's README guide correctly. The guide tells you put PATH related operation in .bash_profile or .profile. But eval "$(pyenv init -)" in .bashrc.

Move pyenv init script from .bash_profile to .bashrc.

# Put it in .bashrc

# PyEnv
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

Extended Reading

You bash shell is not a login shell. .bash_profile is not sourced at all, which skip pyenv init -.

Bash initialization

  1. login mode:
    1. /etc/profile
    2. ~/.bash_profile, ~/.bash_login, ~/.profile (only the first one that exists)
  2. interactive non-login:
    1. /etc/bash.bashrc (some Linux; not on Mac OS X)
    2. ~/.bashrc
  3. non-interactive:
    1. source file in $BASH_ENV

The default shell on Linux is a non-login, interactive shell. The default shell on macOS is a login, interactive shell.

There's also a detailed explanation about the shell startup by flowblok

Ref

Related