The question is about shell setup for virtualenvwrapper, an extension to virtualenv (python guide).

Similar questions had been asked many times but with a lot with different answers:

Which is the "best" way to trigger environment setup and function definition script, considering several possible options:

  1. ~/.profile
  2. ~./.bash_profile, ~/.zprofile
  3. ~./bash_login, ~./zlogin (esoteric option)
  4. ~/.bashrc, ~/.zshrc

The virtualenvwrapper guide states:

"Add three lines to your shell startup file (.bashrc, .profile, etc.) to set the location where the virtual environments should live"

Before considering available options, it is important to consider possible "Use-Cases":

  • terminal (console) login (without X, locally)
  • ssh remote login (interactive)
  • ssh remote command execution (non interactive)
  • after a "graphical" login (GDM), opening a terminal (gnome-terminal)
  • directly in DE (Gnome), via "desktop" file Exec invocation
  • indirectly invoked from xclient (e.g. emacs subprocess)
  • stated as cron job for the user
  • registered as systemd service (or socket) for non-root user
  • indirectly started by a service subprocess (e.g. httpd CGI)

In order to support X graphical login, the only way to set the path is via ~/.profile, that gets sources by /etc/gdm/Xsession, after /etc/profile

While this is the best place for path and environment setting, it fails to define correctly virtualenvwrapper functions ("workon")

The reason is that Xsession is executed under POSIX /bin/sh shell, that is not supported by virtualenvwrapper (bash, zsh, ksh support)

Some distro adopted dash as POSIX shell, while other still rely on POSIX-mode bash invocation.


for non bash/zsh/ksh exclusion.

In X logins, using ~/.profile for (manual) environment settings works:

export WORKON_HOME=~/.virtualenvs
export ENV_NAME='myvirtualenv'
export PATH="$VIRTUAL_ENV/bin:$PATH"

the virtualenvwrapper function definition does not work;

source `which virtualenvwrapper.sh`

A alternative could be to put everything in ~/bashrc

export WORKON_HOME=~/.virtualenvs
export ENV_NAME='myvirtualenv'
source `which virtualenvwrapper.sh`

workon $ENV_NAME

But this DOES NOT WORK also:

  1. X (gnome-shell) does not get initialized, so .desktop files exec command with the "system" environment, not the virtual one.
  2. the environment set by some process (emacs) is destroyed by ~/.bashrc override

An example:

A better option could be a mixed solution (not so cool ...)

In ~/.profile, manual environment setting

export WORKON_HOME=~/.virtualenvs
export ENV_NAME='myvirtualenv'
export PATH="$VIRTUAL_ENV/bin:$PATH"

In ~/.bash_profile or ~/.zprofile, include POSIX profile and function definition:

[ -f ~/.profile ] && source ~/.profile
[ -f `which virtualenvwrapper.sh` ] && source `which virtualenvwrapper.sh`

In gnome-terminal, enabling the "login-shell" option, the "workon" functions gets defined.

For remote execution it is possible to trigger profile inclusion in this way:

ssh localhost bash --login -c env

Maybe something similar could be done for systemd and cron invocation.


All this configuration stuff looks ugly and hard to maintain. Is it possible a better solution ?

  • maybe also LD_LIBRARY_PATH should be prepended in ~/.profile – hute37 Nov 20 '15 at 20:55

But, after all, why should virtualenv be active in global gnome-shell context ?

This would surely break all system-level python application installed.

So the only safe way to start a virtualenv application is to start from a terminal shell

Probably it is safer to activate environment in the ~/.bash_profile ~/.zprofile, enabling login-shell option in terminal.

The alternative setting, using ~/.bashrc, should be avoided because it can cause problems in subshells.


  • enable the login-option
  • start the terminal (or bash/zsh --login in xterm ...)
  • "workon"
  • then start emacs (server) from the terminal shell.

To run a virtualenv application from gnome-shell, the desktop file must exec a dedicated wrapper script that source env activate before execution.

For a generic wrapper (similar to ruby 'bundle exec' and rvm stuff), see:

Maybe a 're-hash' is required ...

  • Having two shells (bash,zsh), one can point bash to "system-wide" virtualenv in /usr/local/lib/pythonenvs and zsh to "user" virtualenv in ~/.virtualenvs. Useful to test deployment. The same configuration could be applied to RVM – hute37 Nov 21 '15 at 11:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.