blob: 042ed8eff842a074c1c8035d754fa8b47f452eb2 [file] [log] [blame]
Vinay Sajip7ded1f02012-05-26 03:45:29 +01001:mod:`venv` --- Creation of virtual environments
2================================================
3
4.. module:: venv
5 :synopsis: Creation of virtual environments.
6.. moduleauthor:: Vinay Sajip <vinay_sajip@yahoo.co.uk>
7.. sectionauthor:: Vinay Sajip <vinay_sajip@yahoo.co.uk>
8
9
10.. index:: pair: Environments; virtual
11
12.. versionadded:: 3.3
13
Ned Deily38861202013-06-11 14:38:39 -070014**Source code:** :source:`Lib/venv`
Vinay Sajip7ded1f02012-05-26 03:45:29 +010015
16--------------
17
Georg Brandldbab58f2012-06-24 16:37:59 +020018The :mod:`venv` module provides support for creating lightweight "virtual
19environments" with their own site directories, optionally isolated from system
20site directories. Each virtual environment has its own Python binary (allowing
21creation of environments with various Python versions) and can have its own
22independent set of installed Python packages in its site directories.
23
Vinay Sajipa7045822013-09-06 09:50:43 +010024See :pep:`405` for more information about Python virtual environments.
Vinay Sajip7ded1f02012-05-26 03:45:29 +010025
26Creating virtual environments
27-----------------------------
28
Vinay Sajipc4618e32012-07-10 08:21:07 +010029.. include:: /using/venv-create.inc
Vinay Sajip7ded1f02012-05-26 03:45:29 +010030
Vinay Sajipa945ad12012-07-09 09:24:59 +010031
Vinay Sajipcd9b7462012-07-09 10:37:01 +010032.. _venv-def:
33
Vinay Sajipa945ad12012-07-09 09:24:59 +010034.. note:: A virtual environment (also called a ``venv``) is a Python
35 environment such that the Python interpreter, libraries and scripts
36 installed into it are isolated from those installed in other virtual
37 environments, and (by default) any libraries installed in a "system" Python,
38 i.e. one which is installed as part of your operating system.
39
40 A venv is a directory tree which contains Python executable files and
41 other files which indicate that it is a venv.
42
Vinay Sajipc4618e32012-07-10 08:21:07 +010043 Common installation tools such as ``Distribute`` and ``pip`` work as
Vinay Sajipa945ad12012-07-09 09:24:59 +010044 expected with venvs - i.e. when a venv is active, they install Python
45 packages into the venv without needing to be told to do so explicitly.
Vinay Sajipc4618e32012-07-10 08:21:07 +010046 Of course, you need to install them into the venv first: this could be
47 done by running ``distribute_setup.py`` with the venv activated,
48 followed by running ``easy_install pip``. Alternatively, you could download
49 the source tarballs and run ``python setup.py install`` after unpacking,
50 with the venv activated.
Vinay Sajipa945ad12012-07-09 09:24:59 +010051
52 When a venv is active (i.e. the venv's Python interpreter is running), the
53 attributes :attr:`sys.prefix` and :attr:`sys.exec_prefix` point to the base
54 directory of the venv, whereas :attr:`sys.base_prefix` and
55 :attr:`sys.base_exec_prefix` point to the non-venv Python installation
56 which was used to create the venv. If a venv is not active, then
57 :attr:`sys.prefix` is the same as :attr:`sys.base_prefix` and
58 :attr:`sys.exec_prefix` is the same as :attr:`sys.base_exec_prefix` (they
59 all point to a non-venv Python installation).
60
Georg Brandl521ed522013-05-12 12:36:07 +020061 When a venv is active, any options that change the installation path will be
62 ignored from all distutils configuration files to prevent projects being
63 inadvertently installed outside of the virtual environment.
64
Vinay Sajipa7045822013-09-06 09:50:43 +010065 When working in a command shell, users can make a venv active by running an
66 ``activate`` script in the venv's executables directory (the precise filename
67 is shell-dependent), which prepends the venv's directory for executables to
68 the ``PATH`` environment variable for the running shell. There should be no
69 need in other circumstances to activate a venv -- scripts installed into
70 venvs have a shebang line which points to the venv's Python interpreter. This
71 means that the script will run with that interpreter regardless of the value
72 of ``PATH``. On Windows, shebang line processing is supported if you have the
73 Python Launcher for Windows installed (this was added to Python in 3.3 - see
74 :pep:`397` for more details). Thus, double-clicking an installed script in
75 a Windows Explorer window should run the script with the correct interpreter
76 without there needing to be any reference to its venv in ``PATH``.
77
Vinay Sajip7ded1f02012-05-26 03:45:29 +010078
79API
80---
81
Vinay Sajip7ded1f02012-05-26 03:45:29 +010082.. highlight:: python
83
Georg Brandldbab58f2012-06-24 16:37:59 +020084The high-level method described above makes use of a simple API which provides
85mechanisms for third-party virtual environment creators to customize environment
86creation according to their needs, the :class:`EnvBuilder` class.
Vinay Sajip7ded1f02012-05-26 03:45:29 +010087
Georg Brandldbab58f2012-06-24 16:37:59 +020088.. class:: EnvBuilder(system_site_packages=False, clear=False, symlinks=False, upgrade=False)
Vinay Sajip7ded1f02012-05-26 03:45:29 +010089
Georg Brandldbab58f2012-06-24 16:37:59 +020090 The :class:`EnvBuilder` class accepts the following keyword arguments on
91 instantiation:
Vinay Sajip7ded1f02012-05-26 03:45:29 +010092
Georg Brandldbab58f2012-06-24 16:37:59 +020093 * ``system_site_packages`` -- a Boolean value indicating that the system Python
94 site-packages should be available to the environment (defaults to ``False``).
Vinay Sajip7ded1f02012-05-26 03:45:29 +010095
Vinay Sajipbd40d3e2012-10-11 17:22:45 +010096 * ``clear`` -- a Boolean value which, if True, will delete the contents of
97 any existing target directory, before creating the environment.
Vinay Sajip7ded1f02012-05-26 03:45:29 +010098
Georg Brandldbab58f2012-06-24 16:37:59 +020099 * ``symlinks`` -- a Boolean value indicating whether to attempt to symlink the
100 Python binary (and any necessary DLLs or other binaries,
101 e.g. ``pythonw.exe``), rather than copying. Defaults to ``True`` on Linux and
Vinay Sajip90db6612012-07-17 17:33:46 +0100102 Unix systems, but ``False`` on Windows.
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100103
Vinay Sajipa945ad12012-07-09 09:24:59 +0100104 * ``upgrade`` -- a Boolean value which, if True, will upgrade an existing
105 environment with the running Python - for use when that Python has been
106 upgraded in-place (defaults to ``False``).
107
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100108
Georg Brandldbab58f2012-06-24 16:37:59 +0200109 Creators of third-party virtual environment tools will be free to use the
110 provided ``EnvBuilder`` class as a base class.
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100111
Georg Brandldbab58f2012-06-24 16:37:59 +0200112 The returned env-builder is an object which has a method, ``create``:
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100113
Georg Brandldbab58f2012-06-24 16:37:59 +0200114 .. method:: create(env_dir)
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100115
Georg Brandldbab58f2012-06-24 16:37:59 +0200116 This method takes as required argument the path (absolute or relative to
117 the current directory) of the target directory which is to contain the
118 virtual environment. The ``create`` method will either create the
119 environment in the specified directory, or raise an appropriate
120 exception.
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100121
Georg Brandldbab58f2012-06-24 16:37:59 +0200122 The ``create`` method of the ``EnvBuilder`` class illustrates the hooks
123 available for subclass customization::
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100124
Georg Brandldbab58f2012-06-24 16:37:59 +0200125 def create(self, env_dir):
126 """
127 Create a virtualized Python environment in a directory.
128 env_dir is the target directory to create an environment in.
129 """
130 env_dir = os.path.abspath(env_dir)
Georg Brandla0b79232013-10-06 12:52:49 +0200131 context = self.ensure_directories(env_dir)
Georg Brandldbab58f2012-06-24 16:37:59 +0200132 self.create_configuration(context)
133 self.setup_python(context)
134 self.setup_scripts(context)
135 self.post_setup(context)
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100136
Georg Brandla0b79232013-10-06 12:52:49 +0200137 Each of the methods :meth:`ensure_directories`,
Georg Brandldbab58f2012-06-24 16:37:59 +0200138 :meth:`create_configuration`, :meth:`setup_python`,
139 :meth:`setup_scripts` and :meth:`post_setup` can be overridden.
140
Vinay Sajip577d4ff2013-07-12 21:52:51 +0100141 .. method:: ensure_directories(env_dir)
Georg Brandldbab58f2012-06-24 16:37:59 +0200142
143 Creates the environment directory and all necessary directories, and
144 returns a context object. This is just a holder for attributes (such as
Vinay Sajip577d4ff2013-07-12 21:52:51 +0100145 paths), for use by the other methods. The directories are allowed to
146 exist already, as long as either ``clear`` or ``upgrade`` were
147 specified to allow operating on an existing environment directory.
Georg Brandldbab58f2012-06-24 16:37:59 +0200148
149 .. method:: create_configuration(context)
150
151 Creates the ``pyvenv.cfg`` configuration file in the environment.
152
153 .. method:: setup_python(context)
154
155 Creates a copy of the Python executable (and, under Windows, DLLs) in
Vinay Sajip577d4ff2013-07-12 21:52:51 +0100156 the environment. On a POSIX system, if a specific executable
157 ``python3.x`` was used, symlinks to ``python`` and ``python3`` will be
158 created pointing to that executable, unless files with those names
159 already exist.
Georg Brandldbab58f2012-06-24 16:37:59 +0200160
161 .. method:: setup_scripts(context)
162
163 Installs activation scripts appropriate to the platform into the virtual
164 environment.
165
166 .. method:: post_setup(context)
167
168 A placeholder method which can be overridden in third party
169 implementations to pre-install packages in the virtual environment or
170 perform other post-creation steps.
171
172 In addition, :class:`EnvBuilder` provides this utility method that can be
173 called from :meth:`setup_scripts` or :meth:`post_setup` in subclasses to
174 assist in installing custom scripts into the virtual environment.
175
176 .. method:: install_scripts(context, path)
177
178 *path* is the path to a directory that should contain subdirectories
179 "common", "posix", "nt", each containing scripts destined for the bin
180 directory in the environment. The contents of "common" and the
181 directory corresponding to :data:`os.name` are copied after some text
182 replacement of placeholders:
183
184 * ``__VENV_DIR__`` is replaced with the absolute path of the environment
185 directory.
186
187 * ``__VENV_NAME__`` is replaced with the environment name (final path
188 segment of environment directory).
189
Vinay Sajipdff9e252013-10-02 11:36:16 +0100190 * ``__VENV_PROMPT__`` is replaced with the prompt (the environment
191 name surrounded by parentheses and with a following space)
192
Georg Brandldbab58f2012-06-24 16:37:59 +0200193 * ``__VENV_BIN_NAME__`` is replaced with the name of the bin directory
194 (either ``bin`` or ``Scripts``).
195
196 * ``__VENV_PYTHON__`` is replaced with the absolute path of the
197 environment's executable.
198
Vinay Sajip577d4ff2013-07-12 21:52:51 +0100199 The directories are allowed to exist (for when an existing environment
200 is being upgraded).
Georg Brandldbab58f2012-06-24 16:37:59 +0200201
202There is also a module-level convenience function:
203
204.. function:: create(env_dir, system_site_packages=False, clear=False, symlinks=False)
205
206 Create an :class:`EnvBuilder` with the given keyword arguments, and call its
207 :meth:`~EnvBuilder.create` method with the *env_dir* argument.
Vinay Sajip2b4fcfb2013-01-30 13:44:00 +0000208
209An example of extending ``EnvBuilder``
210--------------------------------------
211
212The following script shows how to extend :class:`EnvBuilder` by implementing a
Vinay Sajip3c557f22013-07-12 20:54:25 +0100213subclass which installs setuptools and pip into a created venv::
Vinay Sajip2b4fcfb2013-01-30 13:44:00 +0000214
215 import os
216 import os.path
217 from subprocess import Popen, PIPE
218 import sys
219 from threading import Thread
220 from urllib.parse import urlparse
221 from urllib.request import urlretrieve
222 import venv
223
Vinay Sajip3c557f22013-07-12 20:54:25 +0100224 class ExtendedEnvBuilder(venv.EnvBuilder):
Vinay Sajip2b4fcfb2013-01-30 13:44:00 +0000225 """
Vinay Sajip3c557f22013-07-12 20:54:25 +0100226 This builder installs setuptools and pip so that you can pip or
Vinay Sajip2b4fcfb2013-01-30 13:44:00 +0000227 easy_install other packages into the created environment.
228
Vinay Sajip3c557f22013-07-12 20:54:25 +0100229 :param nodist: If True, setuptools and pip are not installed into the
230 created environment.
Vinay Sajip2b4fcfb2013-01-30 13:44:00 +0000231 :param nopip: If True, pip is not installed into the created
232 environment.
Vinay Sajip3c557f22013-07-12 20:54:25 +0100233 :param progress: If setuptools or pip are installed, the progress of the
Vinay Sajip2b4fcfb2013-01-30 13:44:00 +0000234 installation can be monitored by passing a progress
235 callable. If specified, it is called with two
236 arguments: a string indicating some progress, and a
237 context indicating where the string is coming from.
238 The context argument can have one of three values:
239 'main', indicating that it is called from virtualize()
240 itself, and 'stdout' and 'stderr', which are obtained
241 by reading lines from the output streams of a subprocess
242 which is used to install the app.
243
244 If a callable is not specified, default progress
245 information is output to sys.stderr.
246 """
247
248 def __init__(self, *args, **kwargs):
249 self.nodist = kwargs.pop('nodist', False)
250 self.nopip = kwargs.pop('nopip', False)
251 self.progress = kwargs.pop('progress', None)
252 self.verbose = kwargs.pop('verbose', False)
253 super().__init__(*args, **kwargs)
254
255 def post_setup(self, context):
256 """
257 Set up any packages which need to be pre-installed into the
258 environment being created.
259
260 :param context: The information for the environment creation request
261 being processed.
262 """
Vinay Sajip3c557f22013-07-12 20:54:25 +0100263 os.environ['VIRTUAL_ENV'] = context.env_dir
Vinay Sajip2b4fcfb2013-01-30 13:44:00 +0000264 if not self.nodist:
Vinay Sajip3c557f22013-07-12 20:54:25 +0100265 self.install_setuptools(context)
266 # Can't install pip without setuptools
267 if not self.nopip and not self.nodist:
Vinay Sajip2b4fcfb2013-01-30 13:44:00 +0000268 self.install_pip(context)
269
270 def reader(self, stream, context):
271 """
272 Read lines from a subprocess' output stream and either pass to a progress
273 callable (if specified) or write progress information to sys.stderr.
274 """
275 progress = self.progress
276 while True:
277 s = stream.readline()
278 if not s:
279 break
280 if progress is not None:
281 progress(s, context)
282 else:
283 if not self.verbose:
284 sys.stderr.write('.')
285 else:
286 sys.stderr.write(s.decode('utf-8'))
287 sys.stderr.flush()
Vinay Sajipad6bb032013-07-12 21:44:35 +0100288 stream.close()
Vinay Sajip2b4fcfb2013-01-30 13:44:00 +0000289
290 def install_script(self, context, name, url):
291 _, _, path, _, _, _ = urlparse(url)
292 fn = os.path.split(path)[-1]
293 binpath = context.bin_path
294 distpath = os.path.join(binpath, fn)
295 # Download script into the env's binaries folder
296 urlretrieve(url, distpath)
297 progress = self.progress
Vinay Sajip3c557f22013-07-12 20:54:25 +0100298 if self.verbose:
299 term = '\n'
Vinay Sajip2b4fcfb2013-01-30 13:44:00 +0000300 else:
Vinay Sajip3c557f22013-07-12 20:54:25 +0100301 term = ''
302 if progress is not None:
303 progress('Installing %s ...%s' % (name, term), 'main')
304 else:
305 sys.stderr.write('Installing %s ...%s' % (name, term))
Vinay Sajip2b4fcfb2013-01-30 13:44:00 +0000306 sys.stderr.flush()
307 # Install in the env
308 args = [context.env_exe, fn]
309 p = Popen(args, stdout=PIPE, stderr=PIPE, cwd=binpath)
310 t1 = Thread(target=self.reader, args=(p.stdout, 'stdout'))
311 t1.start()
312 t2 = Thread(target=self.reader, args=(p.stderr, 'stderr'))
313 t2.start()
314 p.wait()
315 t1.join()
316 t2.join()
317 if progress is not None:
318 progress('done.', 'main')
319 else:
320 sys.stderr.write('done.\n')
321 # Clean up - no longer needed
322 os.unlink(distpath)
323
Vinay Sajip3c557f22013-07-12 20:54:25 +0100324 def install_setuptools(self, context):
Vinay Sajip2b4fcfb2013-01-30 13:44:00 +0000325 """
Vinay Sajip3c557f22013-07-12 20:54:25 +0100326 Install setuptools in the environment.
Vinay Sajip2b4fcfb2013-01-30 13:44:00 +0000327
328 :param context: The information for the environment creation request
329 being processed.
330 """
Vinay Sajip3c557f22013-07-12 20:54:25 +0100331 url = 'https://bitbucket.org/pypa/setuptools/downloads/ez_setup.py'
332 self.install_script(context, 'setuptools', url)
333 # clear up the setuptools archive which gets downloaded
334 pred = lambda o: o.startswith('setuptools-') and o.endswith('.tar.gz')
Vinay Sajip2b4fcfb2013-01-30 13:44:00 +0000335 files = filter(pred, os.listdir(context.bin_path))
336 for f in files:
337 f = os.path.join(context.bin_path, f)
338 os.unlink(f)
339
340 def install_pip(self, context):
341 """
342 Install pip in the environment.
343
344 :param context: The information for the environment creation request
345 being processed.
346 """
347 url = 'https://raw.github.com/pypa/pip/master/contrib/get-pip.py'
348 self.install_script(context, 'pip', url)
349
350 def main(args=None):
351 compatible = True
352 if sys.version_info < (3, 3):
353 compatible = False
354 elif not hasattr(sys, 'base_prefix'):
355 compatible = False
356 if not compatible:
357 raise ValueError('This script is only for use with '
358 'Python 3.3 or later')
359 else:
360 import argparse
361
362 parser = argparse.ArgumentParser(prog=__name__,
363 description='Creates virtual Python '
364 'environments in one or '
365 'more target '
366 'directories.')
367 parser.add_argument('dirs', metavar='ENV_DIR', nargs='+',
368 help='A directory to create the environment in.')
Vinay Sajip3c557f22013-07-12 20:54:25 +0100369 parser.add_argument('--no-setuptools', default=False,
Vinay Sajip2b4fcfb2013-01-30 13:44:00 +0000370 action='store_true', dest='nodist',
Vinay Sajip3c557f22013-07-12 20:54:25 +0100371 help="Don't install setuptools or pip in the "
372 "virtual environment.")
Vinay Sajip2b4fcfb2013-01-30 13:44:00 +0000373 parser.add_argument('--no-pip', default=False,
374 action='store_true', dest='nopip',
375 help="Don't install pip in the virtual "
376 "environment.")
377 parser.add_argument('--system-site-packages', default=False,
378 action='store_true', dest='system_site',
379 help='Give the virtual environment access to the '
380 'system site-packages dir.')
381 if os.name == 'nt':
382 use_symlinks = False
383 else:
384 use_symlinks = True
385 parser.add_argument('--symlinks', default=use_symlinks,
386 action='store_true', dest='symlinks',
387 help='Try to use symlinks rather than copies, '
388 'when symlinks are not the default for '
389 'the platform.')
390 parser.add_argument('--clear', default=False, action='store_true',
391 dest='clear', help='Delete the contents of the '
392 'environment directory if it '
393 'already exists, before '
394 'environment creation.')
395 parser.add_argument('--upgrade', default=False, action='store_true',
396 dest='upgrade', help='Upgrade the environment '
397 'directory to use this version '
398 'of Python, assuming Python '
399 'has been upgraded in-place.')
400 parser.add_argument('--verbose', default=False, action='store_true',
401 dest='verbose', help='Display the output '
402 'from the scripts which '
Vinay Sajip3c557f22013-07-12 20:54:25 +0100403 'install setuptools and pip.')
Vinay Sajip2b4fcfb2013-01-30 13:44:00 +0000404 options = parser.parse_args(args)
405 if options.upgrade and options.clear:
406 raise ValueError('you cannot supply --upgrade and --clear together.')
Vinay Sajip3c557f22013-07-12 20:54:25 +0100407 builder = ExtendedEnvBuilder(system_site_packages=options.system_site,
Vinay Sajip2b4fcfb2013-01-30 13:44:00 +0000408 clear=options.clear,
409 symlinks=options.symlinks,
410 upgrade=options.upgrade,
411 nodist=options.nodist,
412 nopip=options.nopip,
413 verbose=options.verbose)
414 for d in options.dirs:
415 builder.create(d)
416
417 if __name__ == '__main__':
418 rc = 1
419 try:
420 main()
421 rc = 0
422 except Exception as e:
423 print('Error: %s' % e, file=sys.stderr)
424 sys.exit(rc)
425
Vinay Sajip3c557f22013-07-12 20:54:25 +0100426
Vinay Sajip2b4fcfb2013-01-30 13:44:00 +0000427This script is also available for download `online
428<https://gist.github.com/4673395>`_.