what’s the difference between pyenv, virtualenv, virtualenvwrapper

My first post was about Python ‘virtualenv‘ – started with what is a virtual environment, why we need it, and a minimal example.  The purpose was to clarify beginners about what they get to see in almost every Python example. After that I also wrote about pyenv, and virualenvwrapper, felt like I may have enhanced the confusion here, all the starters might be having the question – what’s the difference between pyenv, virtualenv, virtualenvwrapper ? hence the today’s post title.
As you all know already that a virtual environment is ” a separate Python interpreter with its own set of installed packages.”


is basically a separate Python interpreter with its own set of installed packages. It is the Python interpreter along with the installed packages (other than standard libraries) which make the environment – so we can have multiple Python environments on a single machine, the environments other the default are termed as virtual environment, which we need to create and activate before we can use (as demonstrated here). A note from official docs:
” A virtual environment (also called a venv) is a Python environment such that the Python interpreter, libraries and scripts installed into it are isolated from those installed in other virtual environments, and (by default) any libraries installed in a “system” Python, i.e. one which is installed as part of your operating system.”


is same as virtualenv, it comes with Python standard distribution since version 3.4. It uses the venv module underneath.


is just a wrapper (an extension) around the virtualenv, with intent to provide a cross platform better management of venv. For more read – “Better management of Python virutal environments with virtualenvwrapper“.

4.  pyenv

(previously known as pythonbrew)- to put it simply, it’s Python version management tool. pyenv lets you have multiple Python installations i.e. multiple Python versions, from which you can set the global Python version (the default version to use), and also the local Python version i.e. project/application specific. Apart from this you can also create virtualenv – it has a separate sub-command for it.
Once installed, penv is a bash command not needing python to for execution – it’s user-level command, so no need to use sudo.
To sum up, pyenv is a superset of virtualenv. There’s a detailed post about pyenv setup and usage – ‘pyenv – managing multiple Python versions‘.

Vagrantfile explained

Post’s pre-requisites:

You must understand each and every word in ‘vagrant up‘, otherwise the following text won’t make much sense to you.

A minimal Vagrantfile: Let’s start with a minimal Vagrantfile, which you’ll get on executing vagrant init hashicorp/precise64 (show the file ??) :

# -*- mode: ruby -*-
# vi: set ft=ruby :# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
# The most common configuration options are documented and commented below.
# For a complete reference, please see the online documentation at
# https://docs.vagrantup.com.# Every Vagrant development environment requires a box. You can search for
# boxes at https://atlas.hashicorp.com/search.
config.vm.box = "hashicorp/precise64"# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs
# `vagrant box outdated`. This is not recommended.
# config.vm.box_check_update = false# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:8080" will access port 80 on the guest machine.
# config.vm.network "forwarded_port", guest: 80, host: 8080# Create a private network, which allows host-only access to the machine
# using a specific IP.
# config.vm.network "private_network", ip: ""# Create a public network, which generally matched to bridged network.
# Bridged networks make the machine appear as another physical device on
# your network.
# config.vm.network "public_network"# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
# config.vm.synced_folder "../data", "/vagrant_data"

# Provider-specific configuration so you can fine-tune various
# backing providers for Vagrant. These expose provider-specific options.
# Example for VirtualBox:
# config.vm.provider "virtualbox" do |vb|
# # Display the VirtualBox GUI when booting the machine
# vb.gui = true
# # Customize the amount of memory on the VM:
# vb.memory = "1024"
# end
# View the documentation for the provider you are using for more
# information on available options.

# Define a Vagrant Push strategy for pushing to Atlas. Other push strategies
# such as FTP and Heroku are also available. See the documentation at
# https://docs.vagrantup.com/v2/push/atlas.html for more information.
# config.push.define "atlas" do |push|
# end

# Enable provisioning with a shell script. Additional provisioners such as
# Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
# documentation for more information about their specific syntax and use.
# config.vm.provision "shell", inline: <<-SHELL
# apt-get update
# apt-get install -y apache2
The above file has so many scary lines, but in fact it has only two configuration lines (lot of other commented lines) i.e. removing the commented part makes it:
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/precise64"
Vagrant API version – The line 1 is Vagrant API version specification – Vagrant requires explicit mention of the API versions in the configuration file, to stay backward compatible. So in every Vagrantfile we need to specify which version to use. The current one is version 2 which works with Vagrant 1.1 and up.
The line 1 and 3 enclose all the configuration in Vagrantfile i.e. the first line is specifying the version and staring a block, and ‘end’ specify the block closing.
config.vm.box = "hashicorp/precise64"
Here it is specified, what Vagrant box to use. precise64 by hashicorp is a publicly available basic Ubuntu 12.04 (32 and 64-bit) box good for minimal use cases (you see it in almost every Vagrant post).
The config namespace is mainly about config.vm i.e. the required conf parameters for VM are of form config.vm.*
Config namespace: config.vm
The settings within config.vm modify the configuration of the machine that Vagrant manages.

Looking further – into the commented configuration parameters – The above two lines are enough to get started with your VM, But in case you’re curious, or simply want to check the effect of other configuration options – below is the explanation of all the commented configuration parameters in the file:
config.vm.network – You can set anything related to VM’s network configuration using the ‘config.vm.network’ variable. Configures networks on the machine. Please see the networking page for more information.
config.vm.network "forwarded_port", guest: 80, host: 8080
Creates port forwarding – guest/VM’s port 80 will be accessible on host’s port 8080 i.e. if you have webserver running Apache, or NginX (using port 80), it’ll be accessible from host using localhost:8080.
config.vm.network "private_network", ip: ""
Use this setting to create a private network for VM i.e. will only be accessible via host, specifically using the (above) set IP.
config.vm.network "public_network"
The other type of network we can set for the VM is public network, quite like bridged network – will make the your VM a separate node on your network.

config.vm.synced_folder "../data", "/vagrant_data"

Is for sharing a folder between the host and VM i.e. the first argument ‘../data’ is the path to the host folder, and the second argument ‘/vagrant_data’ (the name is an example – you can set whatever you want) is the folder on guest/VM. This can be super helpful for sharing files between host and guest, or simply you can work on files while VM is powered-off i.e. simply edit the host copy of the file and it’ll get synced on guest once powered-on.

Provider specific configuration: Provider is the virtualization software Vagrant uses to create a VM, as mentioned in the previous post, Vagrant itself is just a wrapper on top of providers i.e. VitualBox, libvirt, VMWare, etc. The minimal file have the provider configuration commented though it’s a requirement – the reason is, Vagrant takes VirtualBox as the default provider, in case you don’t specify otherwise.

# config.vm.provider "virtualbox" do |vb|
#   vb.gui = true
#   vb.memory = "1024"
# end
config.vm.provider “virtualbox” do |vb| – instructing Vagrant to use VirtualBox as the provider (virualization software). And all the provider specific settings are to be specified after this line and before the block’s end.
vb.gui = true – It’ll enable the VirtualBox GUI (Graphical User-Interface) for this machine. Not setting it or, setting it to false runs the machine in headless mode i.e. there’ll be no UI for the virtual machine visible on the host machine.
vb.memory = “1024” – explicitly specifying to allocate 1 GB of RAM for the VM.
Apart this we can specify these customizations in VBoxManage (Vagrant itself uses VBoxManage utility for setting VM specific parameters before booting it up) format:
config.vm.provider :virtualbox do |v|
v.customize ["modifyvm", :id, "--memory", 2048]
v.customize ["modifyvm", :id, "--cpus", 4]
Where modifyvm is the VBoxManage command name, which takes VM id (the GUI for the VM) as param, and next are the options ‘–memory’, ‘–cpu’, followed by the value you want it to set – the VBoxManage command ‘d be:
$ VBoxManage modifyvm 'id/name' --memory 2048

Provisioner-specific configuration: Vagrant requires a provisioner to finally provision the machine, this happens after you run ‘vagrant up‘.  Provisioner can be any of the openly available configuration management tools, like Chef, Puppet, or simply a shell script. Vagrant requires Provisioners to automatically install software, alter configurations, and more on the machine as part of the vagrant provision and coming live process.

# config.vm.provision "shell", inline: <<-SHELL
# apt-get update
# apt-get install -y apache2

config.vm.provision “shell” – specifying simple shell provisioner, with inline mode i.e. specifying the commands to run here too. Here Vagrant has been instructed to run update, followed by Apache 2 installation. You can also use a separate shell script, and specify the path to it in this block:

config.vm.provision "shell" do |sh|
sh.path "provision/setup_apache.sh"

The setup_apache.sh:


echo "Provisioning First VM ..."

echo "Updating ...."
apt-get update

echo "Installing Apache2 ..."
apt-get install -y apache2

In case of any confusion, let me know in the comment section.

Vagrant: VirtualBox and Guest Additions version

One last thing about Vagrant (setup and installation) I want to share with you guys is, syncing the VirtualBox and Guest Additions versions. I hope you’re here after going through the previous Vagrant posts ‘Installing Vagrant on CentOS 7‘ and ‘Vagrant 101‘ – on setting up the first VM (i.e. precise64), when you executed the ‘vagrant up’ for the first time, you may end up getting the following warning message:
$ vagrant up
default: Checking for guest additions in VM...
default: The guest additions on this VM do not match the installed version of
default: VirtualBox! In most cases this is fine, but in rare cases it can
default: prevent things such as shared folders from working properly. If you see
default: shared folder errors, please make sure the guest additions within the
default: virtual machine match the version of VirtualBox you have installed on
default: your host and reload your VM.
default: Guest Additions Version: 4.2.0
default: VirtualBox Version: 5.1
The screenshot:
This post is about resolving this difference of versions. No need to worry, it’s just about executing one more command i.e. installing the vagrant-vbguest plug-in. Shutdown the machine ‘vagrant halt‘ and then execute the following command in the project directory i.e. where the Vagrantfile is located:
$ vagrant plugin install vagrant-vbguest
We can verify the current version of Guest Additions, using the ‘vbguest’ command:
$ vagrant vbguest
[default] GuestAdditions 5.1.6 running --- OK.
The screenshot:

Verification: on next ‘vagrant up‘ after the ‘Machine booted and ready!‘ it will start downloading the missing packages:
[nahmed@localhost ~]$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
== default: Checking if box 'hashicorp/precise64' is up to date...
== default: Clearing any previously set forwarded ports...
== default: Clearing any previously set network interfaces...
== default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
== default: Forwarding ports...
default: 22 (guest) => 2222 (host) (adapter 1)
== default: Booting VM...
== default: Waiting for machine to boot. This may take a few minutes...
default: SSH address:
default: SSH username: vagrant
default: SSH auth method: private key
== default: Machine booted and ready!
[default] GuestAdditions 5.1.6 running --- OK.
== default: Checking for guest additions in VM...
== default: Mounting shared folders...
default: /vagrant => /home/nahmed
== default: Machine already provisioned. Run `vagrant provision` or use the `--provision`
== default: flag to force provisioning. Provisioners marked to run always will still run.
The screenshot, to share the exact stdout I got:
And that’s it. It hasn’t just fixed the version conflict for just this VM, but also for any provisioning i.e. ‘vagrant up‘ it’ll will check & install the correct guest additions right after booting.

Better management of Python virtual environments with virtualenvwrapper

After writing about ‘what is virtualenv‘  and pyenv  I have been feeling a compulsion to write about the one remaining tool in the family i.e. virtualenvwrapper.
As it is in the name, virtualenvwrapper is just a wrapper (an extension) around the virtualenv. The sole motive behind writing it, is covering the discrepancies or features virtualenv lacks, and biggest issue is managing these virtualenvs. As stated in the official docs, the main value-adding features of virtualenvwrapper are:
  • Organizes all of the virtual environments at a single location.
  • Provides better management of virtualenvs – intuitive commands for creating, deleting, copying virtualenvs.
  • A single command to switch between environments i.e. workon (demonstrated later in the post)
  • User-configurable hooks for all operations (see Per-User Customization).
  • Plugin system for more creating shareable extensions (see Extending Virtualenvwrapper).

Installation and Setup: same as virtualenv, virtualenvwrapper is a python package, and can be installed via pip :

$ sudo pip install virtualenvwrapper
It’ll also install the dependencies:
For Windows, use virtualenvwrapper-win instead:
pip install virtualenvwrapper-win
Some one-time only initialization: the main file (wrapper script) is virtualenvwrapper.sh, you need to add the path to it in your shell startup file. You can get the path to it:

$ which virtualenvwrapper.sh
Next is, add the source path in your shell startup file i.e. ~/.bashrc – can use any file editor or simply execute the following in your shell:
$ echo 'export WORKON_HOME=$HOME/.virtualenvs' >> ~/.bashrc
$ echo 'export PROJECT_HOME=$HOME/projects' >> ~/.bashrc
$ echo 'source /usr/bin/virtualenvwrapper.sh' >> ~/.bashrc
Restart your shell or simple reload the .bashrc file:
$ source ~/.bashrc
WORK_HOME is the directory where virtualenvwrapper will be keeping all the venvs.
The above initialization has activated the script and made available the following commands:

Using virtualenvwrapper: let’s verify the setup and get our hands-on the new venv tool. Start with creating our first venv:

$ mkvirtualenv test_venv

(test_venv) $
mkvirtualenv command will create and activate new venv i.e. test_venv – For exiting the venv, use deactivate:
(test_venv) $ deactivate
To choose among the venvs we have workon <venv_name> command – if we execute it without specifying any venv, it’ll list all the available venvs:
$ workon
To start using/activate a venv, simply:
$ workon test_venv
(test_venv) $
For deleting a venv:
$ rmvirtualenv test_venv
Removing test_venv...

If I have missed something, here is the official documentation for the setup and usage – documentation.

For a full fledged sand-boxed development environment, check out Vagrant.

The story behind ‘vagrant up’ – Vagrant 101

You’re a curios tech guy, who wants to test every new Linux package, or a tech blogger who has an impulsion to write a step-by-step guide for installation of a seemingly complex tool/software, or simply a developer who needs to test some new stack with all the operating system level dependencies, all you need is a lightweight, quickly up, portable development environment. The good news is we have Vagrant – a simple to use virtual machine management tool. With Vagrant setting up a fresh development sandbox is just a matter of few commands – at max 3 step process:
  1. Setup – download and install Vagrant – Installing Vagrant on CentOS 7.
  2. Configure – run vagrant init <box-to-use> Create a single file i.e. ‘Vagrantfile‘, to specify the specs for the virtual machine you want Vagrant to spawn.
  3. Work – simply run ‘vagrant up‘, and a clean development environment will be there.

Some necessary vocabulary

technically Vagrant is itself just a wrapper or management utility on top of virtualization software such as VirtualBox, KVM, or VMware, and around configuration management software such as Chef, Puppet, Ansible, etc. The biggest obstacle newbies face while exploring Vagrant is the vocabulary (which is the case with almost all the tech docs). Here are the main terminologies one needs to be clear about, to get easy with Vagrant:

  • Providers  providers are the basic virtualization technology Vagrant use, as stated above Vagrant itself is just a utility above theses softwares e.g. VirtualBox, KVM, or VMware, etc. The initial Vagrant only supported a single provider i.e. VirtualBox, in later releases (1.1) support for KVM, VMWare, Hyper-V, etc was also added. Since version 1.6, Vagrant also support Docker. Since version 1.6, Vagrant natively supports Docker containers, which in some cases can serve as a substitute for a fully virtualized operating system.
  • Provisioners: are the softwares Vagrant use to configure and provision the VMs. Vagrant supports all the mainstream configuration management tools such as Puppet, Ansible, or Chef, etc. The various supported provisioning softwares – https://www.vagrantup.com/docs/provisioning/
  • Boxes – this term must be disturbing you in almost every post you read about Vagrant. Box (Vagrant Box) is simply a configuration for spawning virtual machines using Vagrant i.e in conventional sense it’s just a template for creating a VM. We can set machine configuration ourselves, as per need, or can simply use any of the publicly available boxes (templates). The vagrant box command utility is available for managing boxes – official docs for vagrant box command. There’s public Vagrant box catalog ‘Discover Vagrant Boxes‘ – makes it easy to search and use Vagrant boxes created by the community. Also check this ‘vagrant.es‘, the website lists boxes, people have been nice enough to share publicly. For more – official vagrant box docs.
  • Vagrantfile – where we specify the configuration for vagrant, about what type of virtual machine we want, once set, executing vagrant up will have our clean development environment up and running.  A single Vagrantfile is required per project. Usually there must be Vagrantfile in the directory you’ll be executing vagrant up (or other vagrant command) – but in case it didn’t find any the, Vagrant will climb up the directory tree to find one. For example: If you executed vagrant in /home/ahmed/projects/foo, it look for a Vagrantfile in the following order, starting from current directory and moving up, until it finds one:
/home/ahmed /projects/foo/Vagrantfile
/home/ahmed /projects/Vagrantfile
/home/ahmed /Vagrantfile
This lookup approach lets you execute vagrant command from any directory in your project. You can also specify and fix the starting directory by setting the environment variable VAGRANT_CWD (in your shell start-up file i.e. ~/.bachrc). For more – official Vagrantfile docs.

Few examples of configuration

For specifying the box to use – precise64  is a publicly available basic Ubuntu 12.04 (32 and 64-bit) box good for minimal use cases (you see it almost every Vagrant post):
config.vm.box = "precise64"
For specifying the provider: Not mandatory as you can specify at run time using –provider flag on with vagrant up command, and it’ll have priority over the one set in Vagrantfile. Apart from it we can set the VAGRANT_DEFAULT_PROVIDER environmental variable in our shell start-up file, it’ll have next priority. Last we can set provider in our conf file:
config.vm.provider :virtualbox
For setting the configuration management tool:
config.vm.provision :puppet
A sample Vagrantfile.
For detailed understanding – Vagrantfile explained

A simple example

Step 1:

Install Vagrant – for this check the previous post ‘Installing Vagrant on CentOS 7

Step 2:

in case of standard box (template) just vagrant init {user}/{box_name} will do – it’ll just create the Vagrantfile in the directory:
$ vagrant init hashicorp/precise64

Step 3:

the provisioning step – executing ‘vagrant up’ for the very first time (for a project or after setting Vagrantfile) will look for the box, in case not found it’ll add it (download it), once added it’ll create and provision the environment/VM. On next instances it’ll just boot/resume the VM (unless the –provision flag is explicitly provided. ).
$ vagrant up
Status command to check the available VMs and their status i.e. powered off or running:
$ vagrant status
Finally, let’s SSH/sign-in into our new VM:
$ vagrant ssh
Shutting down VM: simply type exit to leave the ssh session.
vagrant@precise$ exit
For graceful shutdown – use halt command:
$ vagrant halt
Verify the status:

Installing Vagrant on CentOS 7

Vagrant is virtual machine configuration and provisioning utility – uses VirtualBox, VMWare, KVM, etc for virualization and Puppet, Chef, Ansible, or shell scripts for provisioning.

Pre-requisites for Vagrant – the setup just required VirtualBox to be installed – as Vagrant runs on top of a virtualization software. Here is a previous post – “Install VirtualBox 5.1 for CentOS 7/RHEL 7“. I am also listing the steps/commands here:
# cd /etc/yum.repos.d/
# wget http://download.virtualbox.org/virtualbox/rpm/rhel/virtualbox.repo
# yum update -y
# yum -y install epel-release
# yum -y install gcc make patch  dkms qt libgomp
# yum -y install kernel-headers kernel-devel fontforge binutils glibc-headers glibc-devel
# yum -y install VirtualBox-5.1
Install Vagrant – You can download the Vagrant as per your platform – for this post we’ll be downloading it for CentOS 7. The latest available version is 1.8.6.
# wget https://releases.hashicorp.com/vagrant/1.8.6/vagrant_1.8.6_x86_64.rpm
Once downloaded, install the Vagrant using yum localinstall – like yum install it is good for installing locally available/downloaded packages, and it’ll take care of dependencies i.e. download and install them as needed:
# yum -y localinstall vagrant_1.8.6_x86_64.rpm
Here is the screen-shot of steps I performed:

Verification – if the installation is OK. You can simply execute ‘vagrant‘ or ‘vagrant up‘ – it won’t work without vagrant init executed before it. For more read – ‘The story behind vagrant up‘.
A minimal example:
# vagrant init hashicorp/precise64
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.
# vagrant up
Running it first time will look for the precise64 Vagrant box (will not find it, obviously), and starts adding (downloading) it. Once box is added, it’ll start the provisioning:

Install VirtualBox 5.1 for CentOS 7/RHEL 7

VirtualBox (aka Oracle VM VirtualBox) is an open-source “full virtualization” solution by Oracle Corporation. Basically it is a hypervisor, which makes it possible to install an unmodified OS on top of your existing host OS – these environments are generally termed as virtual machines or guest machines (the base machine the Host). Hypervisors i.e. VirtualBox provide a virtualization layer i.e. making it possible for the guest machines to access the abstracted hardware resources.
Presently, VirtualBox runs on Windows, Linux, Macintosh, and Solaris hosts and supports a large number of guest operating systems including but not limited to Windows (NT 4.0, 2000, XP, Server 2003, Vista, Windows 7, Windows 8, Windows 10), DOS/Windows 3.x, Linux (2.4, 2.6, 3.x and 4.x), Solaris and OpenSolaris, OS/2, and OpenBSD.
Note: if you’re not root, do use sudo.

Installation on CentOS 7

1. Add required repositories:
Download the virtualbox.repo at /etc/yum.repos.d/
# cd /etc/yum.repos.d/

For CentOS/RHEL Systems:
# wget http://download.virtualbox.org/virtualbox/rpm/rhel/virtualbox.repo

For Fedora Systems:
# wget http://download.virtualbox.org/virtualbox/rpm/fedora/virtualbox.repo
Enable EPEL repository – enables installation of lots of open source packages via Yum. As most of the dependencies (you’ll be installing at the next step) require epel repository enabled.
# yum -y install epel-release
RHEL/CentOS 7 64-Bit
# wget http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-8.noarch.rpm
# rpm -ivh epel-release-7-8.noarch.rpm
2. Update, and install the dependencies:
# yum -y update
The dependencies:
# yum -y install gcc make patch  dkms qt libgomp
# yum -y install kernel-headers kernel-devel fontforge binutils glibc-headers glibc-devel
3. Install VirtualBox:
# yum -y install VirtualBox-5.1
4. Verify:
# virtualbox

Note: The above steps will work for RHEL 7 and Fedora as well.

pyenv – managing multiple Python versions

You may be a mid-level Python programmer using Python 2.7.5 for sometime, but also curious about Python 3.x.x, or check for yourself what is this all the Python 2 vs 3 debate over Internet, or simply the new functionalities or conventions being introduced in Python 3.x.x. or, just a Python newbie starting off and all so confused given the Python version debate. Don’t worry, my friends you have been rescued – you can keep multiple versions of Python (as many as you like).
There may be lot ways to install multiple Python versions, in the post I’ll be focusing on doing it using penv. – as it’s the most elegant way to do so.


(previously known as pythonbrew)- to put it simply, it’s Python version management tool. penv lets you have multiple Python installations i.e. multiple Python versions, from which you can set the global Python version (the default version to use), and also the local Python version i.e. project specific. Apart from this you can also create virtualenv – it has a separate sub-command for it.

Once installed, penv is a bash command not needing python to for execution – it’s user-level command, so no need to use sudo.

The dependences

presuming you’re installing it on a fresh CentOS 7 machine – in case you have them installed, start with the installation step (anchor here).
$ sudo yum -y install epel-release
$ sudo yum install git gcc zlib-devel bzip2-devel readline-devel sqlite-devel openssl-devel
If you’re using Ubuntu Server, install all build dependencies like this:
$ sudo apt-get install curl git-core gcc make zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev libssl-dev


Now install pyenv as a regular user:
$ curl -L https://raw.github.com/yyuu/pyenv-installer/master/bin/pyenv-installer | bash
At the end of the installation you’ll get a warning:
WARNING: seems you still have not added 'pyenv' to the load path.

# Load pyenv automatically by adding
# the following to ~/.bash_profile:

export PATH="/home/nahmed/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
You must add the above 3 lines at the end of your ~/.bash_profile (~/.profile in case of Ubuntu)- can use any editor i.e. gedit or if you’re familiar with the command-line use vi or vim, or can add them executing the following commands:
$ echo 'export PATH="$HOME/.pyenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
$ echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bash_profile
Once the above lines are added, restart your shell or simply reload the profile:
On CentOS:
$ source ~/.bash_profile
On Ubuntu Server:
$ source ~/.profile
Mac OS X users can install pyenv using the Homebrew package manager:
$ brew update
$ brew install pyenv

Using pyenv:

To list all available Python versions:
$ pyenv install -l
To list the installed Python versions:
$ pyenv versions
Note: Virtual environments will also show up as versions after they’re added.
To install a new Python version, execute:
$ pyenv install x.x.x 
$ pyenv install 3.4.1
To set the global Python version used for your account, use:
$ pyenv global 3.4.1
Can use pyenv to create virtualenvs:
$ pyenv virtualenv test_venv
For activation or de-activation virtualenv, execute:
$ pyenv activate test_venv
$ pyenv deactivate
To list all the virtualenvs you have created, you may use:
$ pyenv virtualenvs

The full list of pyenv commands. – https://github.com/yyuu/pyenv/blob/master/COMMANDS.md

What is virtualenv, why we need it

For the starter (this is the opening post for the devopspy.com) let’s start with something basic, something confusing, something you see in almost every python code example i.e. virtual environment.
Python is an interpreted language, and for development all we need is a Python interpreter (included in Linux based OS – for Windows can be installed using the provided .msi). Like other programming languages Python has its own way of enhancements i.e. to use functionality not there by default, all we have to do is install the package, using any installation utility – pip (most common way), easy_install, or manual installation. These installed packages may termed as the requirements or the dependencies. These dependencies vary for every project – to get a project working all we need is the environment setup ( i.e. Python and the dependencies installed).

What is a virtual environment ?

is basically a separate Python interpreter with its own set of installed packages. As mentioned above the Python interpreter along with the installed packages make the environment – so we can have multiple Python environments on a single machine, the environments other the default are termed as virtual environment, which we need to create and activate before we can use (demonstrated later).

Why we need it ?

  • There may be projects with conflicting dependencies i.e. Project 1 requires numpy version 1.2, while Project 2 requires the latest 1.11.
  • There are packages which have other packages as their dependencies – usually install the latest version, and you may already have an older version of a dependency for some of your project. You can install and test such package in a virtual environment e.g. pandas installs/upgrades 3 4 other packages.

Setup and a simple Example:

Installing virtualenv:

$ sudo pip install virtualenv
Make a new directory to keep virtual environment (optional – just a good practice):
$ mkdir python-venvs
$ cd python-venvs

Create the new environment:

$ virtualenv venv_project1
virtualenv output

Activating the virtualenv:

The above command will install a standalone version of Python, as well as pip, into an isolated directory structure. It’s a good practice to name the virtual environments descriptively. A directory will be created with the specified name, to install new packages and work inside the virtual environment you need to activate it:
$ source venv/bin/activate
activate virtualenv
Once activated you’ll see the name of the environment in parenthesis before the dollar sign (as in the above screenshot).

Deactivating virtualenv:

once done working in the virtualenv we can exit by deactivating it:
(venv_project1)$ decativate
deactivate virtualenv