venv — Создание виртуальных сред

Добавлено в версии 3.3.


Модуль venv обеспечивает поддержку создания облегченных «виртуальных сред» с собственными каталогами сайтов, дополнительно изолированными от системных каталогов сайтов. Каждая виртуальная среда имеет собственный Python двоичный файл (который соответствует версии двоичного файла, используемый для создания этой среды) и может иметь собственный независимый набор установленных пакетов Python в каталогах сайта.

Дополнительные сведения о PEP 405 виртуальных средах см. в разделе Python.

Создание виртуальных сред

Создание виртуального окружения выполняется с помощью команды venv:

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

Выполнение этой команды создаёт целевой каталог (создаются родительские каталоги, которые ещё не существуют) и помещает в него файл pyvenv.cfg с ключом home, указывающим на установку Python, из которой была запущена команда (общее имя для целевого каталога — .venv). Он также создает подкаталог bin (или Scripts в Windows), содержащий копию/символическую ссылку двоичных/бинарных файлов Python (в зависимости от платформы или аргументов, используемых во время создания среды). Он также создаёт (изначально пустой) подкаталог lib/pythonX.Y/site-packages (в Windows это Lib\site-packages). Если указан существующий каталог, он будет использован повторно.

Не рекомендуется, начиная с версии 3.6: pyvenv был рекомендованным инструментом для создания виртуальных сред для Python 3.3 и 3.4, а также запрещён в Python 3.6.

Изменено в версии 3.5: Теперь для создания виртуальных сред рекомендуется использовать venv.

В Windows вызовите команду venv следующим образом:

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

В качестве альтернативы, если вы настроили переменные PATH и PATHEXT для своей установки Python:

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

Если команда запущена с -h, покажет доступные параметры:

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

Создаёт виртуальную среду Python в одном или нескольких целевых каталогах.

позиционные аргументы:
  ENV_DIR               Каталог в которм создаётся среда.

опциональные аргументы:
  -h, --help            показать это справочное сообщение и выйти
  --system-site-packages
                        Предоставить виртуальной среде доступ к
                        системному каталогу site-packages.
  --symlinks            Пытаться использовать символические ссылки, а не копии,
                        если они не являются стандартными для платформы.
  --copies              Пытаться использовать копии, а не символические ссылки,
                        даже если они используются по умолчанию для платформы.
  --clear               Перед созданием среды удалить содержимое каталога
                        среды, если оно уже существует.
  --upgrade             Обновить каталог среды, чтобы использовать текущую версию Python,
                        предполагая, что Python был обновлен на месте.
  --without-pip         Пропускает установку или обновление pip в виртуальной
                        среде (pip по умолчанию загружается автоматически)
  --prompt PROMPT       Предоставляет альтернативное префикс приглашения
                        для этой среды.

После создания среды её можно активировать, например, создав сценарий активации
в каталоге bin.

Изменено в версии 3.4: По умолчанию устанавливает pip, добавлены параметры --without-pip и --copies

Изменено в версии 3.4: В более ранних версиях, если целевой каталог уже существовал, вызывалась ошибка, если не была указана опция --clear или --upgrade.

Примечание

Хотя символические ссылки поддерживаются в Windows, они не рекомендуются. Особо следует отметить, что двойной щелчок python.exe в проводнике файлов быстро разрешит символическую ссылку и проигнорирует виртуальную среду.

Примечание

В Microsoft Windows может потребоваться включить сценарий Activate.ps1, установив политику выполнения для пользователя. Вы можете сделать это, введя следующую команду PowerShell:

PS C: > Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

См. О политиках исполнения для получения дополнительной информации.

Созданный файл pyvenv.cfg также включает ключ include-system-site-packages, для которого установлено значение true, если venv запускается с параметром --system-site-packages, в противном случае — false.

Если не задана опция --without-pip, ensurepip будет вызываться для начальной загрузки pip в виртуальную среду.

venv можно указать несколько путей, и в этом случае идентичная виртуальная среда будет создана в соответствии с заданными параметрами на каждом предоставленном пути.

После создания виртуальной среды её можно «активировать» с помощью сценария в двоичном каталоге виртуальной среды. Вызов сценария зависит от платформы (<venv> необходимо заменить на путь к каталогу, содержащему виртуальную среду):

Платформа Шелл Команда для активации виртуального окружения
POSIX bash/zsh $ source <venv>/bin/activate
  fish $ . <venv>/bin/activate.fish
  csh/tcsh $ source <venv>/bin/activate.csh
  PowerShell Core $ <venv>/bin/Activate.ps1
Windows cmd.exe C:\> <venv>\Scripts\activate.bat
  PowerShell PS C:\> <venv>\Scripts\Activate.ps1

Вам не нужно специально активировать среду; активация просто добавляет двоичный каталог виртуальной среды к вашему пути, так что «python» вызывает интерпретатор Python виртуальной среды, и вы можете запускать установленные сценарии без необходимости использовать их полный путь. Однако все сценарии, установленные в виртуальной среде, должны запускаться без её активации и автоматически запускаться с Python виртуальной среды.

Вы можете деактивировать виртуальную среду, набрав «deactivate» в оболочке. Точный механизм зависит от платформы и является внутренней деталью реализации (обычно используется сценарий или функция оболочки).

Добавлено в версии 3.4: Скрипты активации fish и csh.

Добавлено в версии 3.8: Сценарии активации PowerShell, установленные под POSIX для поддержки ядра PowerShell.

Примечание

Виртуальная среда — окружающая среда Python, в которой интерпретатор Python, библиотеки и сценарии, установленные в нее, изолированы от установленных в других виртуальных средах и (по умолчанию) любых библиотеках, установленных в «системном» 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 интерпретатор виртуальной среды. Это означает, что сценарий будет выполняться с этим интерпретатором независимо от значение PATH. В Windows обработка строк «шибанг» поддерживается, если установлен Python Запускальщик (Launcher) для Windows (это было добавлено в Python в 3.3 — подробнее см. PEP 397). Таким образом, двойной щелчок по установленному сценарию в окне Проводника Windows должен выполнять сценарий с правильным интерпретатором без необходимости ссылки на его виртуальную среду в PATH.

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 пакеты сайта должны быть доступны среде (по умолчанию — False).
  • clear — логическое значение, которое, если имеет значение true, перед созданием среды удалит содержимое любого существующего целевого каталога.
  • symlinks — логическое значение, указывающее, следует ли пытаться симулировать двоичный файл Python, а не копировать.
  • upgrade — логическое значение, которое, если имеет истинное значение, обновит существующую среду с запущенным Python — для использования при обновлении Python на месте (по умолчанию — False).
  • with_pip — логическое значение, которое, если имеет истинное значение, обеспечивает установку pip в виртуальной среде. Используется ensurepip с опцией --default-pip.
  • prompt — строка, которая будет использоваться после активации виртуальной среды (по умолчанию None означает, что будет использоваться имя каталога среды ).

Изменено в версии 3.4: Добавлен параметр with_pip

Добавлено в версии 3.6: Добавлен параметр prompt

Создатели сторонних средств виртуальной среды смогут свободно использовать предоставленный класс EnvBuilder в качестве базового класса.

Возвращенный env-builder — это объект, имеющий метод create:

create(env_dir)

Создать виртуальную среду, указав целевой каталог (абсолютный или относительный к текущему каталогу), который должен содержать виртуальную среду. Метод create создаст среду в указанном каталоге или создаст соответствующее исключение.

Метод create класса EnvBuilder иллюстрирует хуки, доступные для настройки подкласс:

def create(self, env_dir):
    """
    Создать виртуализированную среду Python в каталоге. env_dir --- целевой каталог
    для создания среды.
    """
    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 в среде. В системах POSIX, если был используемый определенный исполняемый python3.x, будут созданы символьные ссылки на python и python3, указывающие на этот исполняемый файл, если только файлы с такими именами не существуют.

setup_scripts(context)

Устанавливает сценарии активации, соответствующие платформе, в виртуальную среду.

post_setup(context)

Метод-заполнитель, который может быть переопределен в реализациях сторонних производителей для предварительной установки пакетов в виртуальной среде или выполнения других шагов после создания.

Изменено в версии 3.7.2: Windows теперь использует сценарии перенаправителя для python[w].exe вместо копирования фактических двоичных файлов. В 3.7.2 только setup_python() ничего не делает, если не выполняется из построения в исходном дереве.

Изменено в версии 3.7.3: Windows копирует сценарии перенаправителя как часть setup_python() вместо setup_scripts(). В 3.7.2 этого не произошло. При использовании symlinks будут связаны исходные исполняемые файлы.

Кроме того, 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__ заменяется абсолютным путем исполняемого файла среды.

Каталоги могут существовать (при обновлении существующей среды).

Существует также функция удобства на уровне модуля:

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

Создать EnvBuilder с заданными аргументами ключевой и вызовите его метод create() с аргументом env_dir.

Добавлено в версии 3.3.

Изменено в версии 3.4: Добавлен параметр with_pip

Изменено в версии 3.6: Добавлен параметр prompt

Пример расширения EnvBuilder

В следующем сценарии показано, как расширить EnvBuilder путем реализации подкласса, который устанавливает setuptools и pip в созданную виртуальную среду:

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):
    """
    Билдер устанавливает setuptools и pip, чтобы можно было использовать pip или
    easy_install другие пакеты в созданной виртуальной среде.

    :param nodist: Если true, в созданную виртуальную среду не
                   устанавливаются setuptools и pip.
    :param nopip: Если true, pip не устанавливается в созданную
                  виртуальную среду.
    :param progress: Если установлены setuptools или pip, ход установки можно контролировать,
                     передавая вызываемый процесс. Если он указан, он вызывается с двумя аргументами:
                     строка, указывающим на некоторый прогресс, и контекст, указывающим, откуда идет
                     строка. Аргумент контекст может иметь один из трёх значений: 'main',
                     указывающий, что он вызывается из самого virtualize(), и 'stdout' и 'stderr',
                     которые получаются путём считывания строк из выходных потоков подпроцессы,
                     используемый для установки приложения.

                     Если вызываемый объект не указан, в 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):
        """
        Настромит пакеты, которые необходимо предварительно установить в создаваемую
        виртуальную среду.

        :param context: Сведения для обрабатываемого запроса на
                        создание виртуальной среды.
        """
        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):
        """
        Чтение строк из выходного потока подпроцессов и передача в вызываемый процесс
        (если указан) или запись информации о ходе в 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)
        # Загрузить сценарий в папку двоичных файлов виртуальной среды
        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()
        # Установка в виртуальную среду
        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')
        # Очистить - больше не нужно
        os.unlink(distpath)

    def install_setuptools(self, context):
        """
        Установить setuptools в виртуальную среду.

        :param context: Сведения для обрабатываемого запроса на
                        создание виртуальной среды.
        """
        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):
        """
        Установить pip в виртуальную среду.

        :param context: Сведения для обрабатываемого запроса на
                        создание виртуальной среды.
        """
        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)

Этот сценарий также доступен для онлайн загрузки.