For a long time, I have been happily using pyenv as my support infrastructure when setting up a Python environment. But now apparently the powers that be in the Python world have given their blessing to make pipenv the official tool for such things.
The problem I have found with pipenv is that it wants to run in a non-virtualenv environment,
so that it can manage the virtualenvs itself. But usually I really try to avoid using the
system Python for my own projects, as the system usually has assumptions and settings that
may conflict with my intentions or needs. (This is why pyenv is so handy.)
I’ve found a technique that does the minimal steps needed to get pipenv working, using the
system Python installation only for the initial bootstrap.
pyenvThis installs the system packages required for pyenv to build Python from source code,
and include all the extra modules such as SSL, SQLite, curses, etc.
$ sudo apt-get install \
git build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev \
wget curl llvm libncurses5-dev
pyenv itself, and associated pluginsThis uses the very handy pyenv-installer script to set everything up nicely from the
github repos.
$ curl -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | bash
pyenv in our .bash_profile scriptThe exact form of this step may be different for you, as you may have other ways of
initializing your environment, but the commands have to be run someplace in order
for pyenv to run properly.
This method tacks the pyenv initialization commands onto the end of your .bash_profile
script.
$ cat >>~/.bash_profile <<EOD
export PATH="\$HOME/.pyenv/bin:\$PATH"
eval "\$(pyenv init -)"
eval "\$(pyenv virtualenv-init -)"
EOD
Be sure to either re-run your .bash_profile (or whatever init script you added the
commands to) or just log out and back in, to get the environment set up for the next
steps. Something like source $HOME/.bash_profile works well for me.
pipenv support$ sudo apt install python3-pip python3-setuptools
This step is the crucial one. We need to install pipenv as a local (“user”) install,
not in the system area. So we need to tell pip this specifically:
$ python3 -m pip install --user pipenv
pipenv to useUse the version of your choice here; you can see the (very long) list with pyenv install --list. You have to be very specific here.
$ pyenv install 3.6.5 # latest version as of this writing
.local/bin directory to your shell pathWe need to add a specific directory to the shell’s path in order to allow us to
run pipenv without using the full path every time, which would be very annoying.
The command here looks very similar to the one for pyenv in step 3, and as in
that step, you may need to adapt it for your specific environment or tastes.
Also, as in step 3, be sure to re-run your shell init scripts with source ~/.bash_profile
or similar commands.
$ cat >>~/.bash_profile <<EOD
export PATH="\$HOME/.local/bin:\$PATH"
EOD
You can be a little less specific in the version of python you ask for in this step.
pipenv will grab the latest patch version of e.g. Python 3.6 if you ask for just 3.6.
$ mkdir myproject; cd myproject
$ pipenv --python 3.6 # match the version installed in step 6
Now you should be able to follow the rest of the pipenv instructions on creating a Pipfile, etc. (Actually pipenv will have created one for you at this point, so you
can just fill out the rest of what you need inside it.)
Have fun!
At this point my personal technique is to install pipenv directly into the virtual
environment I’m working with, having set it up with pyenv beforehand:
pyenv virtualenv 3.6.5 foo
pyenv local foo
pip install pipenv
I prefer the way that pyenv creates its virtualenvs (more specifically, it lets you control the names of the
virtualenvs instead of appending some random string and throwing it in your .local directory.)
pipenv does complain for some reason about the --system flag being used although I didn’t actually use it.
I found a bug report which mentions that this will be fixed soon, so perhaps there’s no
reason to worry much about it. In any case, pipenv detects that it’s already running
in a virtualenv and works fine with it.
Now if I could only get PyCharm to recognize and use the .python-version file that pyenv creates, I’d be
in for much smoother sailing…
It seems that the bug which thinks the --system flag has been used,
when it hasn’t, has mutated into a more serious version that causes
pipenv to abort in a couple different circumstances. Fortunately,
until this is properly fixed (as I believe it will be shortly), there is a
monkeypatch which will work for now.
To patch this, you need to find where pipenv is actually installed.
In my case (with pyenv) I can use $PYENV_VIRTUAL_ENV/lib/python*/site-packages/pipenv. This bug seems to be specific to pyenv (from my
limited experience) so that may be all you need.
Within the site-packages/pipenv directory, you need to edit core.py.
There are two lines that need to be edited, in a similar fashion. In
my version of pipenv these are lines 1322 and 1349. They are both
if statements; the first one is an elif and the other one is a
standard if.
The condition they are testing needs to be changed from
system or allow_global to (system or allow_global) and not PIPENV_VIRTUALENV.
This should fix the problem, as far as I can see. May your luck be as good or better than mine. :)
The problem seems to be fixed in pyenv’s github repo, but hasn’t been released yet. Currently I am using the following command to install pipenv (this checks out a specific git commit from the pyenv repo, so it will quickly be out of date):
pip install git+https://github.com/pypa/pipenv.git@1afee9a118982a46d570e8ce7ce00dfd37f8da85
There is a new release of pipenv to the pypi package index, which
seems to have solved the aforementioned errors. Installing the specific
git commit is therefore no longer necessary.