Christos Hadjinikolis
Christos Hadjinikolis

Reputation: 2158

pyenv install with .python-version and .python-virtualen fails on MacOS BigSur

This is only partly related to #1737

I have just upgraded to the new MAC OS BigSur.

I have installed XCode Beta 12.3 and configured it with Command Line Tools 12.3 beta.

If I do:

$ CFLAGS="-I$(brew --prefix openssl)/include -I$(brew --prefix bzip2)/include -I$(brew --prefix readline)/include -I$(xcrun --show-sdk-path)/usr/include" LDFLAGS="-L$(brew --prefix openssl)/lib -L$(brew --prefix readline)/lib -L$(brew --prefix zlib)/lib -L$(brew --prefix bzip2)/lib" pyenv install --patch 3.8.0 < <(curl -sSL https://github.com/python/cpython/commit/8ea6353.patch\?full_index\=1) as per the instructions of this blog: https://dev.to/kojikanao/install-python-3-8-0-via-pyenv-on-bigsur-4oee It works.

However, I started using pyenv after finding a very attractive way of managing many python envs through automatic activation as described in this blog: https://glhuilli.github.io/virtual-environments.html

Since I upgraded, I have not been able to get this to work.

Questions:

  1. When I cd into a directory with .python-version and .python-virtualenv, the script prompts me to create a new env with pyenv install. This fails with the ./Modules/pwdmodule.c error. How can I alter the above script in order to create an environment using .python-version and .python-virtualenv? I can obviously provide a different python version in the script, but what about the name of the virtual environment? How can I include that?
  2. I want the new virtual environment contents to be located in the directory where pyenv is called and not /Users/username/.pyenv. How can this be done? i am sure others are facing similar issues. Will these be fixed eventually? Ideally, I would like to be able to just do pyenv install and be done...

Thanks in advance.

Upvotes: 1

Views: 2022

Answers (1)

Christos Hadjinikolis
Christos Hadjinikolis

Reputation: 2158

So, about question 1: The answer is that pyenv install will not work at the momment. However, as long as the required pyenv version is installed, the script will work like a charm. So you will have to install it in a different way (not with pyenv install).

Example: Suppose you are given two files:

.python-vesion
.python-virtualenv

respectively encapsulating: 3.8.2 and test-venv. Then just run:

CFLAGS="-I$(brew --prefix openssl)/include -I$(brew --prefix bzip2)/include -I$(brew --prefix readline)/include -I$(xcrun --show-sdk-path)/usr/include" 
LDFLAGS="-L$(brew --prefix openssl)/lib -L$(brew --prefix readline)/lib -L$(brew --prefix zlib)/lib -L$(brew --prefix bzip2)/lib" 
pyenv install --patch \$(head -n 1 .python-version) < <(curl -sSL https://github.com/python/cpython/commit/8ea6353.patch\?full_index\=1)

This should successfully install a pyenv for 3.8.2.

Then just do:

pyenv virtualenv \$(head -n 1 .python-virtualenv)

Then if you run:

\$ pyenv virtualenvs
  3.8.2/envs/test-venv (created from /Users/{your-pc-name}/.pyenv/versions/3.8.2)
  test-venv (created from /Users/{your-pc-name}/.pyenv/versions/3.8.2)

you will confirm that the new env has been created.

About question 2: Here is the updated script:

# If you come from bash you might have to change your $PATH.
# export PATH=$HOME/bin:/usr/local/bin:$PATH
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"

# Automatic venv activation
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
export PYENV_VIRTUALENV_DISABLE_PROMPT=1
# Undo any existing alias for `cd`
unalias cd 2>/dev/null

# Method that verifies all requirements and activates the virtualenv
hasAndSetVirtualenv() {
  # .python-version is mandatory for .python-virtualenv but not vice versa
  if [ -f .python-virtualenv ]; then
    if [ ! -f .python-version ]; then
      echo "To use .python-virtualenv you need a .python-version"
      return 1
    fi
  fi
  # Check if pyenv has the Python version needed.
  # If not (or pyenv not available) exit with code 1 and the respective instructions.
  if [ -f .python-version ]; then
    if [ -z "`which pyenv`" ]; then
      echo "Install pyenv see https://github.com/yyuu/pyenv"
      return 1
    elif [ -n "`pyenv versions 2>&1 | grep 'not installed'`" ]; then
      # Message "not installed" is automatically generated by `pyenv versions`
      echo 'run "pyenv install"'
      return 1
    fi
  fi
  # Create and activate the virtualenv if all conditions above are successful
  # Also, if virtualenv is already created, then just activate it.
  if [ -f .python-virtualenv ]; then
    VIRTUALENV_NAME="`cat .python-virtualenv`"
    PYTHON_VERSION="`cat .python-version`"
    MY_ENV=$PYENV_ROOT/versions/$PYTHON_VERSION/envs/$VIRTUALENV_NAME
    ([ -d $MY_ENV ] || virtualenv $MY_ENV -p `which python`) && \
    source $MY_ENV/bin/activate
  fi
}
pythonVirtualenvCd () {
  # move to a folder + run the pyenv + virtualenv script
  cd "$@" && hasAndSetVirtualenv
}
# Every time you move to a folder, run the pyenv + virtualenv script
alias cd="pythonVirtualenvCd"

Upvotes: 1

Related Questions