blob: 5cd209c06146e489a9a3be36811b27de2b1ffe94 [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
14**Source code:** :source:`Lib/venv.py`
15
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 Sajip7ded1f02012-05-26 03:45:29 +010024
25Creating virtual environments
26-----------------------------
27
Vinay Sajipc4618e32012-07-10 08:21:07 +010028.. include:: /using/venv-create.inc
Vinay Sajip7ded1f02012-05-26 03:45:29 +010029
Vinay Sajipa945ad12012-07-09 09:24:59 +010030
Vinay Sajipcd9b7462012-07-09 10:37:01 +010031.. _venv-def:
32
Vinay Sajipa945ad12012-07-09 09:24:59 +010033.. note:: A virtual environment (also called a ``venv``) is a Python
34 environment such that the Python interpreter, libraries and scripts
35 installed into it are isolated from those installed in other virtual
36 environments, and (by default) any libraries installed in a "system" Python,
37 i.e. one which is installed as part of your operating system.
38
39 A venv is a directory tree which contains Python executable files and
40 other files which indicate that it is a venv.
41
Vinay Sajipc4618e32012-07-10 08:21:07 +010042 Common installation tools such as ``Distribute`` and ``pip`` work as
Vinay Sajipa945ad12012-07-09 09:24:59 +010043 expected with venvs - i.e. when a venv is active, they install Python
44 packages into the venv without needing to be told to do so explicitly.
Vinay Sajipc4618e32012-07-10 08:21:07 +010045 Of course, you need to install them into the venv first: this could be
46 done by running ``distribute_setup.py`` with the venv activated,
47 followed by running ``easy_install pip``. Alternatively, you could download
48 the source tarballs and run ``python setup.py install`` after unpacking,
49 with the venv activated.
Vinay Sajipa945ad12012-07-09 09:24:59 +010050
51 When a venv is active (i.e. the venv's Python interpreter is running), the
52 attributes :attr:`sys.prefix` and :attr:`sys.exec_prefix` point to the base
53 directory of the venv, whereas :attr:`sys.base_prefix` and
54 :attr:`sys.base_exec_prefix` point to the non-venv Python installation
55 which was used to create the venv. If a venv is not active, then
56 :attr:`sys.prefix` is the same as :attr:`sys.base_prefix` and
57 :attr:`sys.exec_prefix` is the same as :attr:`sys.base_exec_prefix` (they
58 all point to a non-venv Python installation).
59
Vinay Sajip7ded1f02012-05-26 03:45:29 +010060
61API
62---
63
Vinay Sajip7ded1f02012-05-26 03:45:29 +010064.. highlight:: python
65
Georg Brandldbab58f2012-06-24 16:37:59 +020066The high-level method described above makes use of a simple API which provides
67mechanisms for third-party virtual environment creators to customize environment
68creation according to their needs, the :class:`EnvBuilder` class.
Vinay Sajip7ded1f02012-05-26 03:45:29 +010069
Georg Brandldbab58f2012-06-24 16:37:59 +020070.. class:: EnvBuilder(system_site_packages=False, clear=False, symlinks=False, upgrade=False)
Vinay Sajip7ded1f02012-05-26 03:45:29 +010071
Georg Brandldbab58f2012-06-24 16:37:59 +020072 The :class:`EnvBuilder` class accepts the following keyword arguments on
73 instantiation:
Vinay Sajip7ded1f02012-05-26 03:45:29 +010074
Georg Brandldbab58f2012-06-24 16:37:59 +020075 * ``system_site_packages`` -- a Boolean value indicating that the system Python
76 site-packages should be available to the environment (defaults to ``False``).
Vinay Sajip7ded1f02012-05-26 03:45:29 +010077
Vinay Sajipbd40d3e2012-10-11 17:22:45 +010078 * ``clear`` -- a Boolean value which, if True, will delete the contents of
79 any existing target directory, before creating the environment.
Vinay Sajip7ded1f02012-05-26 03:45:29 +010080
Georg Brandldbab58f2012-06-24 16:37:59 +020081 * ``symlinks`` -- a Boolean value indicating whether to attempt to symlink the
82 Python binary (and any necessary DLLs or other binaries,
83 e.g. ``pythonw.exe``), rather than copying. Defaults to ``True`` on Linux and
Vinay Sajip90db6612012-07-17 17:33:46 +010084 Unix systems, but ``False`` on Windows.
Vinay Sajip7ded1f02012-05-26 03:45:29 +010085
Vinay Sajipa945ad12012-07-09 09:24:59 +010086 * ``upgrade`` -- a Boolean value which, if True, will upgrade an existing
87 environment with the running Python - for use when that Python has been
88 upgraded in-place (defaults to ``False``).
89
Vinay Sajip7ded1f02012-05-26 03:45:29 +010090
Georg Brandldbab58f2012-06-24 16:37:59 +020091 Creators of third-party virtual environment tools will be free to use the
92 provided ``EnvBuilder`` class as a base class.
Vinay Sajip7ded1f02012-05-26 03:45:29 +010093
Georg Brandldbab58f2012-06-24 16:37:59 +020094 The returned env-builder is an object which has a method, ``create``:
Vinay Sajip7ded1f02012-05-26 03:45:29 +010095
Georg Brandldbab58f2012-06-24 16:37:59 +020096 .. method:: create(env_dir)
Vinay Sajip7ded1f02012-05-26 03:45:29 +010097
Georg Brandldbab58f2012-06-24 16:37:59 +020098 This method takes as required argument the path (absolute or relative to
99 the current directory) of the target directory which is to contain the
100 virtual environment. The ``create`` method will either create the
101 environment in the specified directory, or raise an appropriate
102 exception.
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100103
Georg Brandldbab58f2012-06-24 16:37:59 +0200104 The ``create`` method of the ``EnvBuilder`` class illustrates the hooks
105 available for subclass customization::
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100106
Georg Brandldbab58f2012-06-24 16:37:59 +0200107 def create(self, env_dir):
108 """
109 Create a virtualized Python environment in a directory.
110 env_dir is the target directory to create an environment in.
111 """
112 env_dir = os.path.abspath(env_dir)
113 context = self.create_directories(env_dir)
114 self.create_configuration(context)
115 self.setup_python(context)
116 self.setup_scripts(context)
117 self.post_setup(context)
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100118
Georg Brandldbab58f2012-06-24 16:37:59 +0200119 Each of the methods :meth:`create_directories`,
120 :meth:`create_configuration`, :meth:`setup_python`,
121 :meth:`setup_scripts` and :meth:`post_setup` can be overridden.
122
123 .. method:: create_directories(env_dir)
124
125 Creates the environment directory and all necessary directories, and
126 returns a context object. This is just a holder for attributes (such as
127 paths), for use by the other methods.
128
129 .. method:: create_configuration(context)
130
131 Creates the ``pyvenv.cfg`` configuration file in the environment.
132
133 .. method:: setup_python(context)
134
135 Creates a copy of the Python executable (and, under Windows, DLLs) in
136 the environment.
137
138 .. method:: setup_scripts(context)
139
140 Installs activation scripts appropriate to the platform into the virtual
141 environment.
142
143 .. method:: post_setup(context)
144
145 A placeholder method which can be overridden in third party
146 implementations to pre-install packages in the virtual environment or
147 perform other post-creation steps.
148
149 In addition, :class:`EnvBuilder` provides this utility method that can be
150 called from :meth:`setup_scripts` or :meth:`post_setup` in subclasses to
151 assist in installing custom scripts into the virtual environment.
152
153 .. method:: install_scripts(context, path)
154
155 *path* is the path to a directory that should contain subdirectories
156 "common", "posix", "nt", each containing scripts destined for the bin
157 directory in the environment. The contents of "common" and the
158 directory corresponding to :data:`os.name` are copied after some text
159 replacement of placeholders:
160
161 * ``__VENV_DIR__`` is replaced with the absolute path of the environment
162 directory.
163
164 * ``__VENV_NAME__`` is replaced with the environment name (final path
165 segment of environment directory).
166
167 * ``__VENV_BIN_NAME__`` is replaced with the name of the bin directory
168 (either ``bin`` or ``Scripts``).
169
170 * ``__VENV_PYTHON__`` is replaced with the absolute path of the
171 environment's executable.
172
173
174There is also a module-level convenience function:
175
176.. function:: create(env_dir, system_site_packages=False, clear=False, symlinks=False)
177
178 Create an :class:`EnvBuilder` with the given keyword arguments, and call its
179 :meth:`~EnvBuilder.create` method with the *env_dir* argument.
Vinay Sajip2b4fcfb2013-01-30 13:44:00 +0000180
181An example of extending ``EnvBuilder``
182--------------------------------------
183
184The following script shows how to extend :class:`EnvBuilder` by implementing a
185subclass which installs Distribute and pip into a created venv::
186
187 import os
188 import os.path
189 from subprocess import Popen, PIPE
190 import sys
191 from threading import Thread
192 from urllib.parse import urlparse
193 from urllib.request import urlretrieve
194 import venv
195
196 class DistributeEnvBuilder(venv.EnvBuilder):
197 """
198 This builder installs Distribute and pip so that you can pip or
199 easy_install other packages into the created environment.
200
201 :param nodist: If True, Distribute is not installed into the created
202 environment.
203 :param nopip: If True, pip is not installed into the created
204 environment.
205 :param progress: If Distribute or pip are installed, the progress of the
206 installation can be monitored by passing a progress
207 callable. If specified, it is called with two
208 arguments: a string indicating some progress, and a
209 context indicating where the string is coming from.
210 The context argument can have one of three values:
211 'main', indicating that it is called from virtualize()
212 itself, and 'stdout' and 'stderr', which are obtained
213 by reading lines from the output streams of a subprocess
214 which is used to install the app.
215
216 If a callable is not specified, default progress
217 information is output to sys.stderr.
218 """
219
220 def __init__(self, *args, **kwargs):
221 self.nodist = kwargs.pop('nodist', False)
222 self.nopip = kwargs.pop('nopip', False)
223 self.progress = kwargs.pop('progress', None)
224 self.verbose = kwargs.pop('verbose', False)
225 super().__init__(*args, **kwargs)
226
227 def post_setup(self, context):
228 """
229 Set up any packages which need to be pre-installed into the
230 environment being created.
231
232 :param context: The information for the environment creation request
233 being processed.
234 """
235 if not self.nodist:
236 self.install_distribute(context)
237 if not self.nopip:
238 self.install_pip(context)
239
240 def reader(self, stream, context):
241 """
242 Read lines from a subprocess' output stream and either pass to a progress
243 callable (if specified) or write progress information to sys.stderr.
244 """
245 progress = self.progress
246 while True:
247 s = stream.readline()
248 if not s:
249 break
250 if progress is not None:
251 progress(s, context)
252 else:
253 if not self.verbose:
254 sys.stderr.write('.')
255 else:
256 sys.stderr.write(s.decode('utf-8'))
257 sys.stderr.flush()
258
259 def install_script(self, context, name, url):
260 _, _, path, _, _, _ = urlparse(url)
261 fn = os.path.split(path)[-1]
262 binpath = context.bin_path
263 distpath = os.path.join(binpath, fn)
264 # Download script into the env's binaries folder
265 urlretrieve(url, distpath)
266 progress = self.progress
267 if progress is not None:
268 progress('Installing %s' %name, 'main')
269 else:
270 sys.stderr.write('Installing %s ' % name)
271 sys.stderr.flush()
272 # Install in the env
273 args = [context.env_exe, fn]
274 p = Popen(args, stdout=PIPE, stderr=PIPE, cwd=binpath)
275 t1 = Thread(target=self.reader, args=(p.stdout, 'stdout'))
276 t1.start()
277 t2 = Thread(target=self.reader, args=(p.stderr, 'stderr'))
278 t2.start()
279 p.wait()
280 t1.join()
281 t2.join()
282 if progress is not None:
283 progress('done.', 'main')
284 else:
285 sys.stderr.write('done.\n')
286 # Clean up - no longer needed
287 os.unlink(distpath)
288
289 def install_distribute(self, context):
290 """
291 Install Distribute in the environment.
292
293 :param context: The information for the environment creation request
294 being processed.
295 """
296 url = 'http://python-distribute.org/distribute_setup.py'
297 self.install_script(context, 'distribute', url)
298 # clear up the distribute archive which gets downloaded
299 pred = lambda o: o.startswith('distribute-') and o.endswith('.tar.gz')
300 files = filter(pred, os.listdir(context.bin_path))
301 for f in files:
302 f = os.path.join(context.bin_path, f)
303 os.unlink(f)
304
305 def install_pip(self, context):
306 """
307 Install pip in the environment.
308
309 :param context: The information for the environment creation request
310 being processed.
311 """
312 url = 'https://raw.github.com/pypa/pip/master/contrib/get-pip.py'
313 self.install_script(context, 'pip', url)
314
315 def main(args=None):
316 compatible = True
317 if sys.version_info < (3, 3):
318 compatible = False
319 elif not hasattr(sys, 'base_prefix'):
320 compatible = False
321 if not compatible:
322 raise ValueError('This script is only for use with '
323 'Python 3.3 or later')
324 else:
325 import argparse
326
327 parser = argparse.ArgumentParser(prog=__name__,
328 description='Creates virtual Python '
329 'environments in one or '
330 'more target '
331 'directories.')
332 parser.add_argument('dirs', metavar='ENV_DIR', nargs='+',
333 help='A directory to create the environment in.')
334 parser.add_argument('--no-distribute', default=False,
335 action='store_true', dest='nodist',
336 help="Don't install Distribute in the virtual "
337 "environment.")
338 parser.add_argument('--no-pip', default=False,
339 action='store_true', dest='nopip',
340 help="Don't install pip in the virtual "
341 "environment.")
342 parser.add_argument('--system-site-packages', default=False,
343 action='store_true', dest='system_site',
344 help='Give the virtual environment access to the '
345 'system site-packages dir.')
346 if os.name == 'nt':
347 use_symlinks = False
348 else:
349 use_symlinks = True
350 parser.add_argument('--symlinks', default=use_symlinks,
351 action='store_true', dest='symlinks',
352 help='Try to use symlinks rather than copies, '
353 'when symlinks are not the default for '
354 'the platform.')
355 parser.add_argument('--clear', default=False, action='store_true',
356 dest='clear', help='Delete the contents of the '
357 'environment directory if it '
358 'already exists, before '
359 'environment creation.')
360 parser.add_argument('--upgrade', default=False, action='store_true',
361 dest='upgrade', help='Upgrade the environment '
362 'directory to use this version '
363 'of Python, assuming Python '
364 'has been upgraded in-place.')
365 parser.add_argument('--verbose', default=False, action='store_true',
366 dest='verbose', help='Display the output '
367 'from the scripts which '
368 'install Distribute and pip.')
369 options = parser.parse_args(args)
370 if options.upgrade and options.clear:
371 raise ValueError('you cannot supply --upgrade and --clear together.')
372 builder = DistributeEnvBuilder(system_site_packages=options.system_site,
373 clear=options.clear,
374 symlinks=options.symlinks,
375 upgrade=options.upgrade,
376 nodist=options.nodist,
377 nopip=options.nopip,
378 verbose=options.verbose)
379 for d in options.dirs:
380 builder.create(d)
381
382 if __name__ == '__main__':
383 rc = 1
384 try:
385 main()
386 rc = 0
387 except Exception as e:
388 print('Error: %s' % e, file=sys.stderr)
389 sys.exit(rc)
390
391This script is also available for download `online
392<https://gist.github.com/4673395>`_.