# Extension Plugins

virtualenvwrapper adds several extension points for modifying its behavior. End-users can use shell scripts or other programs for personal customization (see :ref:scripts). Extensions can also be implemented in Python by using Distribute entry points, making it possible to share common behaviors between systems.

## Defining an Extension

Note

Virtualenvwrapper is delivered with a plugin for creating and running the user customization scripts. The examples below are taken from the implementation of that plugin.

### Code Organization

The Python package for virtualenvwrapper is a namespace package. That means multiple libraries can install code into the package, even if they are not distributed together or installed into the same directory. Extensions can (optionally) use the virtualenvwrapper namespace by setting up their source tree like:

• virtualenvwrapper/
• __init__.py
• user_scripts.py

And placing the following code in the __init__.py:

"""virtualenvwrapper module
"""

__import__('pkg_resources').declare_namespace(__name__)


This isn't required, so if you would prefer to use a different namespace that will work, too.

### Extension API

After the package is established, the next step is to create a module to hold the extension code. For example, virtualenvwrapper/user_scripts.py. The module should contain the actual extension entry points. Supporting code can be included, or imported from elsewhere using standard Python code organization techniques.

The API is the same for every extension point. Each uses a Python function that takes a single argument, a list of string arguments passed to the hook loader on the command line. The contents of the argument list are defined for each extension point below (see :ref:plugins-extension-points).

def function_name(args):
# args is a list of strings passed to the hook loader


### Extension Invocation

Plugins can attach to each hook in two different ways. The default is to have an extension function run and do some work directly. For example, the initialize() hook for the user scripts plugin makes sure the scripts exist every time virtualenvwrapper.sh is loaded.

def initialize(args):
for filename, comment in GLOBAL_HOOKS:
make_hook(os.path.join('$WORKON_HOME', filename), comment) return  ### Modifying the User Environment There are cases where the extension needs to update the user's environment (e.g., changing the current working directory or setting environment variables). Modifications to the user environment must be made within the user's current shell, and cannot be run in a separate process. Extensions can define hook functions to return the text of the shell statements to be executed. These source hooks are run after the regular hooks with the same name, and should not do any work of their own. The initialize_source() hook for the user scripts plugin looks for a global initialize script and causes it to be run in the current shell process. def initialize_source(args): return """ # # Run user-provided scripts # [ -f "$WORKON_HOME/initialize" ] && source "$WORKON_HOME/initialize" """  Warning Because the extension is modifying the user's working shell, care must be taken not to corrupt the environment by overwriting existing variable values unexpectedly. Avoid creating temporary variables where possible, and use unique names where necessary. Prefixing variables with the extension name is a good way to manage the namespace. For example, instead of temp_file use user_scripts_temp_file. Use unset to release temporary variable names when they are no longer needed. Warning virtualenvwrapper works under several shells with slightly different syntax (bash, sh, zsh, ksh). Take this portability into account when defining source hooks. Sticking to the simplest possible syntax usually avoids problems, but there may be cases where examining the SHELL environment variable to generate different syntax for each case is the only way to achieve the desired result. ### Registering Entry Points The functions defined in the plugin need to be registered as entry points in order for virtualenvwrapper's hook loader to find them. Distribute entry points are configured in the setup.py for your package by mapping the entry point name to the function in the package that implements it. This partial copy of virtualenvwrapper's setup.py illustrates how the initialize() and initialize_source() entry points are configured. # Bootstrap installation of Distribute import distribute_setup distribute_setup.use_setuptools() from setuptools import setup setup( name = 'virtualenvwrapper', version = '2.0', description = 'Enhancements to virtualenv', # ... details omitted ... entry_points = { 'virtualenvwrapper.initialize': [ 'user_scripts = virtualenvwrapper.user_scripts:initialize', ], 'virtualenvwrapper.initialize_source': [ 'user_scripts = virtualenvwrapper.user_scripts:initialize_source', ], # ... details omitted ... }, )  The entry_points argument to setup() is a dictionary mapping the entry point group names to lists of entry point specifiers. A different group name is defined by virtualenvwrapper for each extension point (see :ref:plugins-extension-points). The entry point specifiers are strings with the syntax name = package.module:function. By convention, the name of each entry point is the plugin name, but that is not required (the names are not used). ### The Hook Loader Extensions are run through a command line application implemented in virtualenvwrapper.hook_loader. Since virtualenvwrapper.sh is the primary caller and users do not typically need to run the app directly, no separate script is installed. Instead, to run the application, use the -m option to the interpreter: $ python -m virtualenvwrapper.hook_loader -h

Manage hooks for virtualenvwrapper

Options:
-h, --help     show this help message and exit
-s, --source   Print the shell commands to be run in the current shell
-q, --quiet    Show less information on the console


### pre_deactivate

The virtualenvwrapper.pre_deactivate hooks are run just before an environment is disabled. \$VIRTUAL_ENV is set to point to the current environment.

### post_deactivate

The virtualenvwrapper.post_deactivate hooks are run just after an environment is disabled. The name of the environment just deactivated is passed as the first argument.

### pre_rmvirtualenv

The virtualenvwrapper.pre_rmvirtualenv hooks are run just before an environment is deleted. The name of the environment being deleted is passed as the first argument.

### post_rmvirtualenv

The virtualenvwrapper.post_rmvirtualenv hooks are run just after an environment is deleted. The name of the environment being deleted is passed as the first argument.