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