I - like most python hackers - use virtualenv on a daily basis. I love virtualenv. It allows me to install packages in a local context, without isolating my development environment completely.


What is vpython

Vpython is a tiny(-ish) bash script to help with your daily virtualenv needs.

  • You don't have to worry about sourcing the activate script.
  • You don't have to point to your virtualenv path.

just use vpython instead of python to invoke scripts "inside" a virtualenv.

How

Vpython works by looking for at virtualenv directory in the directory of the script you invoke. If not found, it will go up one directory and search in the parent. When vpython detects a virtualenv folder, it will use that folder's configuration to run whatever you asked vpython to run, just like had it been python.

$> vpython path/to/project/script.py

Running vpython with first argument being a directory, it will search for a virtualenv directory, just like when invoking it with a script path. When a virtualenv is found, vpython will invoke the virtualenv's python, handing you a python shell for that virtualenv.

$> vpython path/to/project/

If no arguments are given to vpython, it will use you current working directory to search for a virtualenv path.

$> pwd
/home/tbug/src/demo-project
> vpython
Using virtualenv at "/home/tbug/src/demo-project/.virtualenv"
Python 2.7.1+ (r271:86832, Sep 27 2012, 21:12:17)
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>

Use vpython --help to see full help text.

$> vpython --help
Usage:
    vpython --help                                this help
    vpython --pip </path/to/env> [<pip_ags>...]   call the virtualenv pip
    vpython --install </path/to/new/env>          install a new virtualenv
    vpython --find </path/to/search/for/env>      return virtualenv path if found, else exits with non-0
    vpython <python_file>                         call a python file inside a virtualenv
    vpython <directory>                           start a python shell inside a virtualenv

Usecase

This is our folder structure:

/home/tbug/src/demo-project/
|-- .virtualenv
|   +-- { regular virtualenv directory structure here }
+-- script.py

With regular virtualenv, we would do something like

/home/tbug/src/demo-project $> source .virtualenv/bin/activate
/home/tbug/src/demo-project $> python script.py
/home/tbug/src/demo-project $> deactivate

and with vpython

/home/tbug/src/demo-project $> vpython script.py

It might not seem like much to save a line (noone deactivates a virtualenv, right?) and you are right.
The strength of vpython is the ability to look up the virtualenv no matter what path is your current working directory, and even if that script is behind a symlink.

Say our script.py is some utility that we want to use all the time. We might link it somewhere on our path, like /usr/local/bin.

But we still need the virtualenv to activate before the script is run?! What do?!

If we use vpython, the virtualenv configuration will be correctly loaded before running our script.

We can even use vpython in the script's shebang.
Pretend this is our script.py, and that it contains something very useful:

#!vpython
#imaging that we import something useful from our virtualenv site-packages
print "hello vpython world"

Now, if you make that script executable, no matter where you run it from, it will use the correct virtualenv directory. As long as script.py is inside a folder (or subfolder) of a virtualenv directory, it will work.

Let's try symlinking script.py to /usr/local/bin, or wherever you put your stuff:

/home/tbug/src/demo-project $> ln -s `pwd`/script.py /usr/local/bin/script
/home/tbug/src/demo-project $> #it is now liked to our path as "script"
/home/tbug/src/demo-project $> script
Using virtualenv at "/home/tbug/src/demo-project/.virtualenv"
hello vpython world

Note that vpython always tell you where it found the running virtualenv. If you don't want that, you can invoke vpython with the -q or --quiet flag.

Installing vpython

Make sure you have a working python and virtualenv installed (vpython will warn you if they are missing, so don't worry).

  1. Clone the repository from github (https://github.com/tbug/tbug.github.io.git).
  2. Run the installer script (vpython/install.sh).
  3. There is no step 3.

The installer will try to place symlinks to the vpython and vpip scripts in ~/bin if it exists, otherwise it will install it to /usr/bin.

Note that if ~/bin exists, it is assumed that it is also on your $PATH.

Updating vpython

  1. cd to the path of the vpython repo clone.
  2. run git pull.
  3. Once again; no step 3.

Starting a new environment

Vpython also contains wrappers for creating and installing packages inside a virtualenv.

/home/tbug/src/demo-project $> vpython --install .
New python executable in /home/tbug/src/demo-project/.virtualenv/bin/python
Installing setuptools, pip...done.

By default, vpython will install the virtualenv to a folder called virtualenv. You can change this by setting the ENV_NAME environment variable like this:

/home/tbug/src/demo-project $> ENV_NAME=env vpython --install .
New python executable in /home/tbug/src/demo-project/env/bin/python
Installing setuptools, pip...done.

It is only necessary to set this when installing a new environment. When using an existing environment, vpython doesn't care about the environment name.

Now that you have a new environment, it is time to install some packages.

/home/tbug/src/demo-project $> vpython --pip . install asynckit

The syntax here is:

vpython --pip (virtualenv lookup path) (pip arguments...)

This is a bit cumbersome, so vpython ships with the vpip helper.

vpip assumes your current directory is where you want to look for a virtualenv, so if your current working directory is somewhere within a virtualenv, you can use vpip just as regular pip:

/home/tbug/src/demo-project $> vpip install asynckit
Using virtualenv at "/home/tbug/src/demo-project/.virtualenv"
Downloading/unpacking asynckit
..............................
Successfully installed asynckit
Cleaning up...

Something broke!

Oh dear! If you find an error, open an issue, or send me a pull request with a fix.