Using Virtual Environments - Python I
In a previous post I gave virtual environments as a solution to the problem of dependency and version collision for software built using languages like Python, Ruby, Node.js, and Go.
In this post I give the details and examples of using the Python virtual environment. First I walk through everything using OS X–i.e., using a Mac–and then, briefly, I describe the same procedures using Windows.
- Python installation (OS X)
- Creating a python virtual environment
- Activating and deactiving the virtual environment
- Virtual environment creation in Python 3.3 and later
- Adding packages to the virtual environment
- Key Features of virtual environments
- Next steps
- Python virtual environments on Windows
- Next steps (reiterated)
Python installation (OS X)
Python is, typically, installed side by side on a system at the granularity of major and minor releases. For example, on my OS X system I use the package manager1 MacPorts to install new versions of Python. MacPorts installs all its software under the top level directory /opt
. Here are all the Python versions currently installed on my OS X system via MacPorts:
~$ ls /opt/local/Library/Frameworks/Python.framework/Versions/
2.7 3.3 3.4 3.5
OS X comes with Python already installed. I’m still running Mavericks, a.k.a. OS X 10.9.5, and that ships with Python 2.7.5. Usually Apple does not update the system version of Python, and so my system will remain at 2.7.5 (circa 2013) as long as I keep it running Mavericks (also circa 2013).
As you can tell from the directly listing above, I’ve used MacPorts to independently install Python versions 2.7, 3.3, 3.4, and 3.5. Another way to see that is by asking MacPorts to list the Python packages:
~$ port installed python*
The following ports are currently installed:
python2_select @0.0_1 (active)
python3_select @0.0_1 (active)
python27 @2.7.11_0 (active)
python33 @3.3.6_5 (active)
python34 @3.4.4_0 (active)
python35 @3.5.1_0 (active)
python_select @0.3_6 (active)
I installed each of those using a command like:
~$ sudo port install python27
or
~$ sudo port install python35
The various python_select
packages come along with any MacPorts Python package. They provide a command you can use to change the default python package to one selected from the various versions you’ve installed via MacPorts. I don’t use python_select
because I find using virtual environments to be a better mechanism.
Creating a python virtual environment
The Python port maintainers at MacPorts are pretty good about upgrades, and so the Python 2.7 installed in the /opt
tree is likely to be recent. To check that, let’s create a virtual environment for Python 2.7 from MacPorts.
-
Open a terminal window and create an empty directory somewhere–I called mine “using-python-venv”–and
cd
into it. -
Check the path to the Python binary and the Python version. This will be whatever is the default on your system.
~/using-python-venv$ which python /usr/bin/python ~/using-python-venv$ python --version Python 2.7.5
-
Save a record of all the current environment variables (so we can see what changes when the virtual environment is activated) using this command:
~/using-python-venv$ env > orig.env.txt
-
Create the virtual environment deployment directory using this command:[^venvdir]
~/using-python-venv$ /opt/local/Library/Frameworks/Python.framework/Versions/2.7/bin/virtualenv venv27
Note: the path will be different with Fink or Homebrew. If you are using either of those package managers, you’ll need to locate the Python 2.7 installation directory to be used in the command.
Activating and deactiving the virtual environment
-
Activate the virtual environment using this “source” command:
~/using-python-venv$ . venv27/bin/activate (venv27)~/using-python-venv$
Notice that the command prompt now has a parenthetical prefix that shows the active virtual environment deployment directory.
-
Save a record of the new environment variables:
(venv27)~/using-python-venv$ env > venv27.env.txt
-
Check the python path and version version
(venv27)~/using-python-venv$ which python /Users/neo/using-python-venv/venv27/bin/python (venv27)~/using-python-venv$ python --version Python 2.7.11
-
Deactivate the virtual environment using the
deactivate
command:(venv27)~/using-python-venv$ deactivate ~/using-python-venv$
Notice that the command prompt changed to no longer shows the virtual environment deployment directory. And if you try the
deactivate
command again, you’ll get a command not found error. -
Diff the original (default) environment against the new environment to see what changed when the Python virtual environment was activated:
~/using-python-venv$ diff orig.env.txt venv27.env.txt
Here’s the diff output looked like on my system; I used the command
diff orig.env.txt venv27.env.txt
:13a14 > VIRTUAL_ENV=/Users/neo/using-python-venv/venv27 15c16 < PATH=/Users/neo/.rbenv/shims:/Users/neo/bin:/Users/neo/local/bin:/xpt/local/bin:/opt/local/bin:/opt/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin:/usr/texbin:/Applications/git-annex.app/Contents/MacOS --- > PATH=/Users/neo/using-python-venv/venv27/bin:/Users/neo/.rbenv/shims:/Users/neo/bin:/Users/neo/local/bin:/xpt/local/bin:/opt/local/bin:/opt/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin:/usr/texbin:/Applications/git-annex.app/Contents/MacOS 21c22 < PS1=\[\033[1;36m\]$(parse_git_branch)\[\033[1;32m\]\w$\[\033[0m\]\n --- > PS1=(venv27)\[\033[1;36m\]$(parse_git_branch)\[\033[1;32m\]\w$\[\033[0m\]\n
As you can see, activating the virtual environment has an effect. A new environment variable,
VIRTUAL_ENV
, is created and identifies the location of the Python deployment directory. The$PATH
is changed to have the virtual Python environment searched first. And the command line prompt is changed to indicate which Python virtual environment deployment directory is active.
Virtual environment creation in Python 3.3 and later
The virtual environment mechanism is built in to the Python Library in Python version 3.3. and later, in the venv
module. The command to create the virtual environment using the venv
module would be:
~/using-python-venv$ /opt/local/Library/Python.framework/Versions/3.3/bin/python3 -m venv venv33
However, on my Mac using the MacPorts distribution of Python 3.3, the virtual environment that is created has no packages whatsoever. Specifically, it does not have setuptools
or pip
, and both those tools are immensely useful.2
So I continue to use the virtualenv
command, even with Python 3.3 and later, when on my Mac.3 The command to create a 3.3 virtual environment that way is:
~/using-python-venv$ /opt/local/Library/Frameworks/Python.framework/Versions/3.3/bin/virtualenv venv33
Activating the 3.3 virtual environment created with virtualenv
, and using the pip list
command confirms the presence of setuptools
and pip
(albeit slightly outdated).
Adding packages to the virtual environment
When the virtual environment is active you can install packages an not be concerned about polluting the global Python environment or breaking dependencies for any other project or any application installed on the system.
The first thing I usually do after creating a new virtual environment is to activate it and update setuptools
and pip
.
~/using-python-venv$ . venv33/bin/activate
(venv33)~/using-python-venv$ pip list
pip (1.4.1)
setuptools (0.9.8)
(venv33)~/using-python-venv$ pip install --upgrade setuptools
(venv33)~/using-python-venv$ pip install --upgrade pip
venv33)~/using-python-venv$ pip list
pip (8.0.2)
setuptools (20.0)
(venv33)~/using-python-venv$
And now you can install any other packages you need.
Key Features of virtual environments
With these basic steps I have demonstrated the key characteristics of a virtual environment for a project or application. These characteristics are common to all virtual environments, not just for Python.
Virtual environments have:
-
A local, mutable, deployment directory for the execution environment that is independent of the global (system) environment.
With Python, this is accomplished with the
virtualenv
utility or thevenv
module to create and provision a local deployment directory. -
An activation mechanism for standing up the virtual environment—for switching an execution context to use the local deployment directory preferentially ahead of the global environment, or masking the global environment.
With Python virtual environments, this is accomplished using the
activate
script4 to change the search path to look in the local deployment directory before looking in other locations. Theacivate
script also generates thedeactivate
script, changes the CLI prompt to signal that the virtual environment is activate, and adds a specialVIRTUAL_ENV
environment variable to aid virtual environment support in Python itself and in project or application scripting. -
A deactivation mechanism for standing down the virtual environment—for switching the execution context back to using the global environment and ignoring the deployment directory.
As mentioned above, Python virtual environments generate a
deactivate
script to accomplish this. The script self-deletes when executed.
Next steps
In the next post I’ll discuss how to do upgrades of dependencies to pick up patches without picking up major or minor upgrades, how to test for the correct virtual environment and dependency versions in script (e.g. test scripts, build scripts), and how to provision the virtual environment from a list of known dependencies.
Python virtual environments on Windows
Using Python on Windows is only slightly different, but worth describing. In this post I’ll use the standard command window. In the next post I’ll switch to Powershell.
(Windows) Installing Python
Python install kits are available here: https://www.python.org/downloads/windows/. I’ll be using only the 64-bit installers in these examples.
Python 2 and older Python 3 installers use a root directory as the default install location (e.g. C:\Python27
or C:\Python33
). Starting with Python 3.5, the installer places Python in the \Program Files
directory. I like that; it’s in keeping with traditional Windows software installation practices. So when I use the older installers, I change the install directory to match the new convention.
Here’s how to install Python 2.7, create a virtual environment, activate it, update it, and deactivate it from a Command window.
-
Install Python 2.7.11 from the python-2.7.11.amd64.msi installer.
-
When prompted for the install path, set it to
C:\Program Files\Python 2.7
. -
After installing, open a command window using “Run as administrator …” and enter these commands:
C:\>"C:\Program Files\Python 2.7\python.exe" -m pip install --upgrade pip C:\>"C:\Program Files\Python 2.7\python.exe" -m pip install --upgrade setuptools C:\>"C:\Program Files\Python 2.7\python.exe" -m pip install virtualenv
-
Open a new command window (without using “Run as administrator …”) and create a virtual environment inside a new directory using:
C:\>mkdir C:\test C:\>cd C:\test C:\test>mkdir using-python-venv C:\test>cd Using-python-venv C:\test\using-python-venv>"C:\Program Files\Python 2.7\Scripts\virtualenv.exe" venv27
-
Activate the virtual environment using:
C:\test\using-python-venv>venv27\Scripts\activate
-
Check the version and upgrade
setuptools
andpip
:(venv27) C:\test\xx-yy-zz>python --version Python 2.7.11 (venv27) C:\test\xx-yy-zz>pip list pip (8.0.2) setuptools (20.0) wheel (0.29.0) (venv27) C:\test\xx-yy-zz>pip install --upgrade setuptools (venv27) C:\test\xx-yy-zz>pip install --upgrade pip (venv27) C:\test\xx-yy-zz>pip list pip (8.0.2) setuptools (20.0)
-
Deactivate the virtual environment using:
(venv27) C:\test\xx-yy-zz>deactivate C:\test\xx-yy-zz>
Installing Python 3.3 and later is similar, except that the virtual environment is created using the venv
module.
-
Install Python 3.4.4 from the python-3.4.4.amd64.msi installer.
-
When prompted for the install path, set it to
C:\Program Files\Python 3.4
. -
After installing, open a command window using “Run as administrator …” and enter these commands:
C:\>"C:\Program Files\Python 3.4\python.exe" -m pip install --upgrade pip C:\>"C:\Program Files\Python 3.4\python.exe" -m pip install --upgrade setuptools
-
Open a new command window (without using “Run as administrator …”) and create a virtual environment inside a new directory using:
C:\>cd C:\test\using-python-venv C:\test\using-python-venv>"C:\Program Files\Python 3.3\Scripts\python.exe" -m venv venv34
-
Activate the virtual environment using:
C:\test\using-python-venv>venv34\Scripts\activate.bat
-
Check the version and upgrade
setuptools
andpip
:(venv34) C:\test\xx-yy-zz>python --version Python 3.4.4 (venv34) C:\test\xx-yy-zz>pip list pip (7.1.2) setuptools (18.2) You are using pip version 7.1.2, however version 8.0.2 is available. You should consider upgrading via the 'python -m pip install --upgrade pip' command. (venv34) C:\test\xx-yy-zz>python -m pip install --upgrade setuptools (venv34) C:\test\xx-yy-zz>python -m pip install --upgrade pip (venv34) C:\test\xx-yy-zz>python -m pip list pip (8.0.2) setuptools (20.0)
-
Deactivate the virtual environment using:
(venv34) C:\test\xx-yy-zz>deactivate C:\test\xx-yy-zz>
Next steps (reiterated)
In the next post I’ll discuss how to do upgrades of dependencies to pick up patches without picking up major or minor upgrades, how to test for the correct virtual environment and dependency versions in script (e.g. test scripts, build scripts), and how to provision the virtual environment from a list of known dependencies.
-
There are three popular package managers for OS X. MacPorts, HomeBrew, and Fink. All three work well. But I prefer MacPorts or Fink to HomeBrew because both MacPorts and Fink install into alternative directory trees and do not replace or modify the system as originally laid down by Apple. HomeBrew, on the other hand, resets permissions on system files (dangerously giving the current user write authority into privileged locations) and installs into system folders (which can cause issues during operating system upgrades). In short, I view HomeBrew as more intrusive, less stable, and less secure than MacPorts or Fink. ↩
-
You could still use the
venv
module and just download the source forsetuptools
and build it, then use that to download and installpip
. I just find thevirtualenv
utility more expedient. ↩ -
The situation is different for Windows, as is seen later in this post I use the
venv
module to create Python 3.3 (or later) virtual environments on Windows. ↩ -
The activation script is executed via a source command on Unix-like systems, and directly as a batch file or Powershell script on Windows systems. ↩
- show comments