28.3. "venv" --- 仮想環境の作成
*******************************

バージョン 3.3 で追加.

**ソースコード:** Lib/venv/

======================================================================

"venv" モジュールは、軽量な "仮想環境" の作成のサポートを提供します。
仮想環境には、仮想環境ごとの site ディレクトリがあり、これはシステムの
site ディレクトリから分離させることができます。それぞれの仮想環境には
、それ自身の Python バイナリ (様々な Python バージョンで環境を作成でき
ます) があり、仮想環境ごとの site ディレクトリに独立した Python パッケ
ージ群をインストールできます。

Python仮想環境に関してより詳しくは **PEP 405** を参照してください。

注釈:

  "pyvenv" スクリプトは Python 3.6 で非推奨となり、代わりに "python3
  -m venv" を使い、仮想環境を動かす Python インタープリタを取り違える
  可能性を防ぎやすくします。


28.3.1. 仮想環境の作成
======================

仮想環境 を作成するには "venv" コマンドを実行します:

   python3 -m venv /path/to/new/virtual/environment

このコマンドを実行すると、ターゲットディレクトリ (および必要なだけの親
ディレクトリ) が作成され、その中に "pyvenv.cfg" ファイルが置かれます。
そのファイルの "home" キーはこのコマンドを呼び出した Python のインスト
ール場所を指します。 このコマンドはまた、 Python バイナリのコピーまた
はシンボリックリンク (のプラットフォームあるいは仮想環境作成時に使われ
た引数に対して適切な方) を含む "bin"  (Windows では "Scripts") サブデ
ィレクトリを作成します。 さらに、 "lib/pythonX.Y/site-packages"
(Windows では "Lib\site-packages") サブディレクトリも (最初は空の状態
で) 作成します。指定したディレクトリが存在している場合は、それが再利用
されます。

バージョン 3.6 で非推奨: Python 3.3 と 3.4 では、仮想環境の作成に推奨
していたツールは "pyvenv" でしたが、Python 3.6では非推奨です。

バージョン 3.5 で変更: 仮想環境の作成には、 "venv" の使用をお勧めしま
す。

参考:

  Python Packaging User Guide: Creating and using virtual environments

Windows では、 "venv" コマンドは次のように実行します:

   c:\>c:\Python35\python -m venv c:\path\to\myenv

あるいは、 インストールされている Python のために "PATH" 変数や
"PATHEXT" 変数が設定してある場合は次のコマンドでも実行できます:

   c:\>python -m venv c:\path\to\myenv

このコマンドを "-h" をつけて実行すると利用できるオプションが表示されま
す:

   usage: venv [-h] [--system-site-packages] [--symlinks | --copies] [--clear]
               [--upgrade] [--without-pip]
               ENV_DIR [ENV_DIR ...]

   Creates virtual Python environments in one or more target directories.

   positional arguments:
     ENV_DIR               A directory to create the environment in.

   optional arguments:
     -h, --help            show this help message and exit
     --system-site-packages
                           Give the virtual environment access to the system
                           site-packages dir.
     --symlinks            Try to use symlinks rather than copies, when symlinks
                           are not the default for the platform.
     --copies              Try to use copies rather than symlinks, even when
                           symlinks are the default for the platform.
     --clear               Delete the contents of the environment directory if it
                           already exists, before environment creation.
     --upgrade             Upgrade the environment directory to use this version
                           of Python, assuming Python has been upgraded in-place.
     --without-pip         Skips installing or upgrading pip in the virtual
                           environment (pip is bootstrapped by default)

   Once an environment has been created, you may wish to activate it, e.g. by
   sourcing an activate script in its bin directory.

バージョン 3.4 で変更: デフォルトで pip をインストールします。"--
without-pip" と "--copies" オプションを追加しました。

バージョン 3.4 で変更: 以前のバージョンでは、対象となるディレクトリが
既に存在していた場合は、 "--clear" オプションや "--upgrade" オプション
を付けない限りはエラーを送出していました。

作成された "pyvenv.cfg" ファイルには、"include-system-site-packages"
キーも含まれます。これは "venv" が "--system-site-packages" オプション
をつけて実行されたなら "true" で、そうでなければ "false" です。

"--without-pip" オプションが与えられない限り、"pip" を仮想環境でブート
するために "ensurepip" が呼ばれます。

"venv" には複数のパスを渡すことができ、その場合はそれぞれのパスに同一
の仮想環境が作成されます。

仮想環境の作成が完了すれば、その仮想環境のバイナリディレクトリにあるス
クリプトで "有効化" できます。 スクリプトの呼び出し方はプラットフォー
ム固有です (*<venv>* の部分は、仮想環境があるディレクトリのパスに置き
換える必要があります):

+---------------+-------------------+-------------------------------------------+
| プラットフォ  | シェル            | 仮想環境を有効化するためのコマンド        |
| ーム          |                   |                                           |
|===============|===================|===========================================|
| Posix         | bash/zsh          | $ source <venv>/bin/activate              |
+---------------+-------------------+-------------------------------------------+
|               | fish              | $ . <venv>/bin/activate.fish              |
+---------------+-------------------+-------------------------------------------+
|               | csh/tcsh          | $ source <venv>/bin/activate.csh          |
+---------------+-------------------+-------------------------------------------+
| Windows       | cmd.exe           | C:\> <venv>\Scripts\activate.bat          |
+---------------+-------------------+-------------------------------------------+
|               | PowerShell        | PS C:\> <venv>\Scripts\Activate.ps1       |
+---------------+-------------------+-------------------------------------------+

環境を有効化するのに特別な指定は *必要* ありません; 有効化は仮想環境の
バイナリディレクトリをパスの最初に加えて、 "python" で仮想環境の
Python インタプリタが呼び出されるようにし、フルパスを入力せずにインス
トールされたスクリプトを実行できるようにするだけです。 しかし、インス
トールされたすべてのスクリプトは有効化しなくても実行可能で、仮想環境の
Python で自動的に実行されなければなりません。

シェルで "deactivate" と入力することで仮想環境を無効化できます。 厳密
な仕組みはプラットフォーム固有です。 例えば、Bash の有効化スクリプトは
"deactivate" 関数を定義している一方、 Windows では、仮想環境が作成され
るときにインストールされる "deactivate.bat" と "Deactivate.ps1" という
個別のスクリプトがあります。

バージョン 3.4 で追加: "fish" および "csh" 有効化スクリプト。

注釈:

  仮想環境とは、その中にインストールされた Python インタープリタ、ライ
  ブラリ、そしてスクリプトが、他の仮想環境にインストールされたものから
  隔離されている Python 環境です。そして (デフォルトでは) 仮想環境は "
  システム" の Python、すなわち OS の一部としてインストールされた
  Python にインストールされている全てのライブラリからも隔離されていま
  す。仮想環境は、 Python 実行ファイルと、それが仮想環境であることを示
  す幾つかのファイルを含んだディレクトリツリーです。"Setuptools" や
  "pip" などの一般的なインストールツールは期待通りに仮想環境と連係しま
  す。 言い換えると、仮想環境が有効なときには、 Python パッケージを仮
  想環境へインストールするのに、インストールツールへの明示的な指示は必
  要ありません。仮想環境が有効な場合 (すなわち、仮想環境の Python イン
  タープリタを実行しているとき)、 "sys.prefix" と "sys.exec_prefix" は
  仮想環境のベースディレクトリを示します。 代わりに "sys.base_prefix"
  と "sys.base_exec_prefix" が仮想環境を作るときに使った、仮想環境では
  ない環境の Python がインストールされている場所を示します。 仮想環境
  が無効の時は、 "sys.prefix" は "sys.base_prefix" と、
  "sys.exec_prefix" は "sys.base_exec_prefix" と同じになります (全て仮
  想環境ではない環境の Python のインストール場所を示します)。仮想環境
  が有効なときに、不注意で仮想環境の外にプロジェクトがインストールされ
  ることを避けるために、インストールパスを変更するあらゆるオプションは
  distutils の全ての設定ファイルによって無視されます。コマンドシェルで
  作業をしているとき、仮想環境の実行可能ファイルディレクトリにある
  "activate" スクリプト (正確なファイル名はシェル依存です) を実行して
  、仮想環境を有効化できます。 このスクリプトは仮想環境の実行可能ファ
  イルのディレクトリを、実行中のシェルの "PATH" 環境変数の先頭に差し込
  みます。 それ以外の状況では、仮想環境を有効化するための作業は必要無
  いはずです—仮想環境にインストールされたスクリプトには、仮想環境の
  Python インタプリタを指す "shebang" 行があります。 これはつまり、ス
  クリプトは "PATH" の値に関係無く、仮想環境のインタプリタで実行される
  ということです。 Windows では、 Windows 用の Python ランチャがインス
  トールされている場合は "shebang" 行の処理がサポートされています (こ
  の機能はバージョン 3.3 で Python に追加されました - 詳細は **PEP
  397** を参照してください)。 従って、インストールされたスクリプトを
  Windows のエクスプローラのウィンドウからダブルクリックすると、
  "PATH" にその仮想環境への参照を持たせる必要無く、そのスクリプトが正
  しいインタープリタで実行されるはずです。


28.3.2. API
===========

上述の高水準のメソッドは、サードパーティの仮想環境の作成者が環境の作成
を必要に応じてカスタマイズするための機構を提供する簡素な API を利用し
ます。それが "EnvBuilder" クラスです。

class venv.EnvBuilder(system_site_packages=False, clear=False, symlinks=False, upgrade=False, with_pip=False, prompt=None)

   "EnvBuilder" クラスを実体化するときに、以下のキーワード引数を受け取
   ります:

   * "system_site_packages" -- 真偽値で、システムの Python の site-
     packages を仮想環境から利用できるかどうかを示します (デフォルト:
     "False")。

   * "clear" -- 真偽値で、真の場合環境を作成する前に既存の対象ディレク
     トリの中身を削除します。

   * "symlinks" -- 真偽値で、Python のバイナリ (と必要な DLL や
     "pythonw.exe" などのバイナリ) をコピーせずにシンボリックの作成を
     試みるかどうかを示します。

   * "upgrade" -- 真偽値で、真の場合実行中の Python で既存の環境をアッ
     プグレードします。その Python がインプレースでアップグレードされ
     たときに用います。デフォルトは "False" です。

   * "with_pip" -- 真偽値で、真の場合仮想環境に pip がインストールされ
     ていることを保証します。"--default-pip" オプションで  "ensurepip"
     を使用します。

   * "prompt" -- 仮想環境が有効になっているときに使われる文字列 (デフ
     ォルトは "None" で、その環境のディレクトリ名が使われることになり
     ます)。

   バージョン 3.4 で変更: "with_pip" 引数が追加されました。

   バージョン 3.6 で追加: "prompt" 引数が追加されました。

   サードパーティーの仮想環境ツールの作成者は、"EnvBuilder" を継承して
   使うことができます。

   返される env-builder オブジェクトには "create" というメソッドがあり
   ます:

   create(env_dir)

      このメソッドは path (絶対パスあるいは現在のディレクトリからの相
      対パス) を必要な1つの引数と受け取ります。"create" メソッドは指定
      されたディレクトリに仮想環境を構築するか、例外を送出します。

      "EnvBuilder" クラスの "create" メソッドは、サブクラスのカスタマ
      イズに使えるフックを説明します:

         def create(self, env_dir):
             """
             Create a virtualized Python environment in a directory.
             env_dir is the target directory to create an environment in.
             """
             env_dir = os.path.abspath(env_dir)
             context = self.ensure_directories(env_dir)
             self.create_configuration(context)
             self.setup_python(context)
             self.setup_scripts(context)
             self.post_setup(context)

      メソッド "ensure_directories()", "create_configuration()",
      "setup_python()", "setup_scripts()", "post_setup()" はそれぞれオ
      ーバーライドできます。

   ensure_directories(env_dir)

      仮想環境のディレクトリと全ての必要なディレクトリを作成し、コンテ
      キストオブジェクトを返します。 これは (パスなどの) 属性を保持し
      ているだけのオブジェクトで、他のメソッドから使うためのものです。
      既存の仮想環境ディレクトリ上での操作を許可するために "clear" や
      "upgrade" が指定されている場合に限り、作成されるディレクトリは既
      に存在していても構いません。

   create_configuration(context)

      仮想環境に "pyvenv.cfg" 設定ファイルを作成します。

   setup_python(context)

      Python 実行ファイル (および、 Windows では DLL も) のコピーを仮
      想環境に作成します。 POSIX システムで、特定の "python3.x" 実行フ
      ァイルが使われている場合、同じ名前のファイルが既に存在していない
      限り、 "python" および "python3" というシンボリックリンクがその
      実行ファイルを指すように作成されます。

   setup_scripts(context)

      プラットフォームに対応した有効化スクリプトを仮想環境にインストー
      ルします。

   post_setup(context)

      サードパーティーライブラリがオーバーライドするための空のメソッド
      です。このメソッドをオーバーライドして、仮想環境構築後にパッケー
      ジのプリインストールなどのステップを実装できます。

   これらに加えて、 "EnvBuilder" は "setup_scripts()" やサブクラスの
   "post_setup()" が仮想環境にスクリプトをインストールするためのユーテ
   ィリティーメソッドを提供しています。

   install_scripts(context, path)

      *path* は "common", "posix", "nt" ディレクトリを格納したディレク
      トリへのパスです。各サブディレクトリには仮想環境の bin ディレク
      トリにインストールするスクリプトを格納します。 "common" の中身と
      、 "os.name" に一致するディレクトリの中身を、以下の置換処理を行
      いながらコピーします:

      * "__VENV_DIR__" は仮想環境ディレクトリの絶対パスに置換されます
        。

      * "__VENV_NAME__" は仮想環境の名前 (仮想環境ディレクトリのパスの
        最後の部分) に置換されます。

      * "__VENV_PROMPT__" はプロンプトに置換されます (括弧で囲まれ空白
        が続く環境名)。

      * "__VENV_BIN_NAME__" は bin ディレクトリ名 ("bin" か "Scripts")
        に置換されます。

      * "__VENV_PYTHON__" は仮想環境の Python 実行ファイルの絶対パスに
        置換されます。

      (既存環境のアップグレード中は) ディレクトリは存在しても構いませ
      ん。

モジュールレベルの簡易関数もあります:

venv.create(env_dir, system_site_packages=False, clear=False, symlinks=False, with_pip=False)

   "EnvBuilder" を指定されたキーワード引数を使って作成し、その
   "create()" メソッドに *env_dir* 引数を渡して実行します。

   バージョン 3.4 で変更: "with_pip" 引数が追加されました。


28.3.3. "EnvBuilder" を拡張する例
=================================

次のスクリプトで、作成された仮想環境に setuptools と pip をインストー
ルするサブクラスを実装して "EnvBuilder" を拡張する方法を示します:

   import os
   import os.path
   from subprocess import Popen, PIPE
   import sys
   from threading import Thread
   from urllib.parse import urlparse
   from urllib.request import urlretrieve
   import venv

   class ExtendedEnvBuilder(venv.EnvBuilder):
       """
       This builder installs setuptools and pip so that you can pip or
       easy_install other packages into the created virtual environment.

       :param nodist: If True, setuptools and pip are not installed into the
                      created virtual environment.
       :param nopip: If True, pip is not installed into the created
                     virtual environment.
       :param progress: If setuptools or pip are installed, the progress of the
                        installation can be monitored by passing a progress
                        callable. If specified, it is called with two
                        arguments: a string indicating some progress, and a
                        context indicating where the string is coming from.
                        The context argument can have one of three values:
                        'main', indicating that it is called from virtualize()
                        itself, and 'stdout' and 'stderr', which are obtained
                        by reading lines from the output streams of a subprocess
                        which is used to install the app.

                        If a callable is not specified, default progress
                        information is output to sys.stderr.
       """

       def __init__(self, *args, **kwargs):
           self.nodist = kwargs.pop('nodist', False)
           self.nopip = kwargs.pop('nopip', False)
           self.progress = kwargs.pop('progress', None)
           self.verbose = kwargs.pop('verbose', False)
           super().__init__(*args, **kwargs)

       def post_setup(self, context):
           """
           Set up any packages which need to be pre-installed into the
           virtual environment being created.

           :param context: The information for the virtual environment
                           creation request being processed.
           """
           os.environ['VIRTUAL_ENV'] = context.env_dir
           if not self.nodist:
               self.install_setuptools(context)
           # Can't install pip without setuptools
           if not self.nopip and not self.nodist:
               self.install_pip(context)

       def reader(self, stream, context):
           """
           Read lines from a subprocess' output stream and either pass to a progress
           callable (if specified) or write progress information to sys.stderr.
           """
           progress = self.progress
           while True:
               s = stream.readline()
               if not s:
                   break
               if progress is not None:
                   progress(s, context)
               else:
                   if not self.verbose:
                       sys.stderr.write('.')
                   else:
                       sys.stderr.write(s.decode('utf-8'))
                   sys.stderr.flush()
           stream.close()

       def install_script(self, context, name, url):
           _, _, path, _, _, _ = urlparse(url)
           fn = os.path.split(path)[-1]
           binpath = context.bin_path
           distpath = os.path.join(binpath, fn)
           # Download script into the virtual environment's binaries folder
           urlretrieve(url, distpath)
           progress = self.progress
           if self.verbose:
               term = '\n'
           else:
               term = ''
           if progress is not None:
               progress('Installing %s ...%s' % (name, term), 'main')
           else:
               sys.stderr.write('Installing %s ...%s' % (name, term))
               sys.stderr.flush()
           # Install in the virtual environment
           args = [context.env_exe, fn]
           p = Popen(args, stdout=PIPE, stderr=PIPE, cwd=binpath)
           t1 = Thread(target=self.reader, args=(p.stdout, 'stdout'))
           t1.start()
           t2 = Thread(target=self.reader, args=(p.stderr, 'stderr'))
           t2.start()
           p.wait()
           t1.join()
           t2.join()
           if progress is not None:
               progress('done.', 'main')
           else:
               sys.stderr.write('done.\n')
           # Clean up - no longer needed
           os.unlink(distpath)

       def install_setuptools(self, context):
           """
           Install setuptools in the virtual environment.

           :param context: The information for the virtual environment
                           creation request being processed.
           """
           url = 'https://bitbucket.org/pypa/setuptools/downloads/ez_setup.py'
           self.install_script(context, 'setuptools', url)
           # clear up the setuptools archive which gets downloaded
           pred = lambda o: o.startswith('setuptools-') and o.endswith('.tar.gz')
           files = filter(pred, os.listdir(context.bin_path))
           for f in files:
               f = os.path.join(context.bin_path, f)
               os.unlink(f)

       def install_pip(self, context):
           """
           Install pip in the virtual environment.

           :param context: The information for the virtual environment
                           creation request being processed.
           """
           url = 'https://raw.github.com/pypa/pip/master/contrib/get-pip.py'
           self.install_script(context, 'pip', url)

   def main(args=None):
       compatible = True
       if sys.version_info < (3, 3):
           compatible = False
       elif not hasattr(sys, 'base_prefix'):
           compatible = False
       if not compatible:
           raise ValueError('This script is only for use with '
                            'Python 3.3 or later')
       else:
           import argparse

           parser = argparse.ArgumentParser(prog=__name__,
                                            description='Creates virtual Python '
                                                        'environments in one or '
                                                        'more target '
                                                        'directories.')
           parser.add_argument('dirs', metavar='ENV_DIR', nargs='+',
                               help='A directory in which to create the
                                    'virtual environment.')
           parser.add_argument('--no-setuptools', default=False,
                               action='store_true', dest='nodist',
                               help="Don't install setuptools or pip in the "
                                    "virtual environment.")
           parser.add_argument('--no-pip', default=False,
                               action='store_true', dest='nopip',
                               help="Don't install pip in the virtual "
                                    "environment.")
           parser.add_argument('--system-site-packages', default=False,
                               action='store_true', dest='system_site',
                               help='Give the virtual environment access to the '
                                    'system site-packages dir.')
           if os.name == 'nt':
               use_symlinks = False
           else:
               use_symlinks = True
           parser.add_argument('--symlinks', default=use_symlinks,
                               action='store_true', dest='symlinks',
                               help='Try to use symlinks rather than copies, '
                                    'when symlinks are not the default for '
                                    'the platform.')
           parser.add_argument('--clear', default=False, action='store_true',
                               dest='clear', help='Delete the contents of the '
                                                  'virtual environment '
                                                  'directory if it already '
                                                  'exists, before virtual '
                                                  'environment creation.')
           parser.add_argument('--upgrade', default=False, action='store_true',
                               dest='upgrade', help='Upgrade the virtual '
                                                    'environment directory to '
                                                    'use this version of '
                                                    'Python, assuming Python '
                                                    'has been upgraded '
                                                    'in-place.')
           parser.add_argument('--verbose', default=False, action='store_true',
                               dest='verbose', help='Display the output '
                                                  'from the scripts which '
                                                  'install setuptools and pip.')
           options = parser.parse_args(args)
           if options.upgrade and options.clear:
               raise ValueError('you cannot supply --upgrade and --clear together.')
           builder = ExtendedEnvBuilder(system_site_packages=options.system_site,
                                          clear=options.clear,
                                          symlinks=options.symlinks,
                                          upgrade=options.upgrade,
                                          nodist=options.nodist,
                                          nopip=options.nopip,
                                          verbose=options.verbose)
           for d in options.dirs:
               builder.create(d)

   if __name__ == '__main__':
       rc = 1
       try:
           main()
           rc = 0
       except Exception as e:
           print('Error: %s' % e, file=sys.stderr)
       sys.exit(rc)

このスクリプトは オンライン でダウンロードすることも可能です。
