Spec-Zone.ru › Python 3.9

zipapp — Управление исполняемыми Python zip-архивами

Новая в версии 3.5.

Исходный код: Lib/zipapp.py

Этот модуль предоставляет инструменты для управления созданием zip-файлов, содержащих Python-код, который может быть выполнен непосредственно интерпретатором Python. Модуль предоставляет как интерфейс командной строки, так и Python API.

Пример

Следующий пример демонстрирует, как можно использовать интерфейс командной строки для создания исполняемого архива из каталога, содержащего Python-код. При выполнении архив будет выполнять функцию main из модуля myapp в архиве.

$ python -m zipapp myapp -m "myapp:main"
$ python myapp.pyz
<output from myapp>

Интерфейс командной строки

При вызове как программы из командной строки используется следующий формат:

$ python -m zipapp source [options]

Если source — это каталог, это создаст архив из содержимого source. Если source — это файл, он должен быть архивом, и он будет скопирован в целевой архив (или содержимое его строки shebang будет выведено, если указан параметр –info).

Поддерживаются следующие параметры:

-o <output>, --output=<output>

Записать вывод в файл с именем output. Если этот параметр не указан, имя выходного файла будет таким же, как имя входного файла source, с добавленным расширением .pyz. Если указано явное имя файла, оно используется как есть (так что расширение .pyz должно быть включено, если требуется).

Имя выходного файла должно быть указано, если source — это архив (и в этом случае output не должен совпадать с source).

-p <interpreter>, --python=<interpreter>

Добавить строку #! в архив, указав interpreter в качестве команды для выполнения. Также, в POSIX, сделать архив исполняемым. По умолчанию не записывается строка #! и файл не делается исполняемым.

-m <mainfn>, --main=<mainfn>

Записать в архив файл __main__.py, который выполняет mainfn. Аргумент mainfn должен иметь вид «pkg.mod:fn», где «pkg.mod» — это пакет/модуль в архиве, а «fn» — вызываемый объект в данном модуле. Файл __main__.py выполнит этот вызываемый объект.

--main не может быть указан при копировании архива.

-c, --compress

Сжимать файлы с помощью метода deflate, уменьшая размер выходного файла. По умолчанию файлы хранятся в архиве без сжатия.

--compress не имеет эффекта при копировании архива.

Новая в версии 3.7.

--info

Вывести интерпретатор, встроенный в архив, для диагностических целей. В этом случае любые другие параметры игнорируются, а SOURCE должен быть архивом, а не каталогом.

-h, --help

Вывести краткое сообщение об использовании и завершить работу.

Python API

Модуль определяет две удобные функции:

zipapp.create_archive(source, target=None, interpreter=None, main=None, filter=None, compressed=False)

Создать архив приложения из source. Источник может быть любым из следующих:

  • Имя каталога или объект-путь, указывающий на каталог, в этом случае будет создан новый архив приложения из содержимого этого каталога.
  • Имя существующего файла приложения или объект-путь, указывающий на такой файл, в этом случае файл копируется в целевой (изменяя его, чтобы отразить значение, заданное для аргумента interpreter). Имя файла должно включать расширение .pyz , если необходимо.
  • Объект файла, открытый для чтения в режиме байтов. Содержимое файла должно быть архивом приложения, и предполагается, что объект файла расположен в начале архива.

Аргумент target определяет, куда будет записан результирующий архив:

  • Если это имя файла или объект-путь, архив будет записан в этот файл.
  • Если это объект открытого файла, архив будет записан в этот объект файла, который должен быть открыт для записи в режиме байтов.
  • Если параметр target опущен (или None), исходный параметр source должен быть каталогом, и целевой будет файлом с тем же именем, что и исходный, с добавленным расширением .pyz.

Аргумент interpreter указывает имя интерпретатора Python, с помощью которого будет выполняться архив. Он записывается как строка shebang в начале архива. В POSIX это будет интерпретироваться ОС, а в Windows — обработчиком запуска Python. Опускание interpreter приводит к отсутствию записи строки shebang. Если интерпретатор указан, а target — имя файла, биты исполняемости целевого файла будут установлены.

Аргумент main задает имя вызываемого объекта, который будет использоваться в качестве основной программы для архива. Он может быть указан только если источник — это каталог, и исходный каталог не содержит файла __main__.py. Аргумент main должен иметь вид «pkg.module:callable» и архив будет запущен путём импорта «pkg.module» и выполнения заданного вызываемого объекта без аргументов. Опускание main является ошибкой, если исходный каталог не содержит файла __main__.py, так как в противном случае результирующий архив не будет исполняемым.

Необязательный аргумент filter задаёт функцию обратного вызова, которой передаётся объект Path, представляющий путь к файлу, добавляемому (относительно каталога исходного). Он должен возвращать True, если файл должен быть добавлен.

Необязательный аргумент compressed определяет, сжимаются ли файлы. Если он установлен в True, файлы в архиве сжимаются методом deflate; в противном случае файлы хранятся без сжатия. Этот параметр не влияет при копировании существующего архива.

Если для source или target указан объект файла, вызывающий обязан закрыть его после вызова create_archive.

При копировании существующего архива, объекты файлов, предоставленные, должны иметь только read и readline, или write методы. При создании архива из каталога, если целевой объект — объект файла, он будет передан классу zipfile.ZipFile, и должен предоставлять методы, необходимые этому классу.

Новая в версии 3.7: Добавлены аргументы filter и compressed.

zipapp.get_interpreter(archive)

Возвращает интерпретатор, указанный в строке shebang #! в начале архива. Если строка shebang #! отсутствует, возвращает None. Аргумент archive может быть именем файла или объектом файла, открытым для чтения в режиме байтов. Предполагается, что он находится в начале архива.

Примеры

Скомпоновать каталог в архив и запустить его.

$ python -m zipapp myapp
$ python myapp.pyz
<output from myapp>

То же самое можно сделать, используя функцию create_archive():

>>> import zipapp
>>> zipapp.create_archive('myapp', 'myapp.pyz')

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

$ python -m zipapp myapp -p "/usr/bin/env python"
$ ./myapp.pyz
<output from myapp>

Чтобы заменить строку shebang в существующем архиве, создайте изменённый архив, используя функцию create_archive():

>>> import zipapp
>>> zipapp.create_archive('old_archive.pyz', 'new_archive.pyz', '/usr/bin/python3')

Чтобы обновить файл на месте, сделайте замену в памяти с помощью объекта BytesIO, а затем перезапишите исходный файл. Обратите внимание, что существует риск, при перезаписи файла на месте, что ошибка приведёт к потере исходного файла. Данный код не защищает от таких ошибок, но код в производстве должен это сделать. Также этот метод будет работать только если архив помещается в оперативную память:

>>> import zipapp
>>> import io
>>> temp = io.BytesIO()
>>> zipapp.create_archive('myapp.pyz', temp, '/usr/bin/python2')
>>> with open('myapp.pyz', 'wb') as f:
>>>     f.write(temp.getvalue())

Указание интерпретатора

Обратите внимание, что если вы укажете интерпретатор и затем распространите архив своего приложения, вам необходимо убедиться, что используемый интерпретатор портативен. Загрузчик Python для Windows поддерживает большинство распространённых форм POSIX #! строки, но есть и другие моменты, которые следует учитывать:

  • Если вы используете «/usr/bin/env python» (или другие формы команды «python», такие как «/usr/bin/python»), вам необходимо учесть, что у ваших пользователей может быть установлен как Python 2, так и Python 3 по умолчанию, и напишите свой код, чтобы он работал в обеих версиях.
  • Если вы используете явную версию, например «/usr/bin/env python3», ваше приложение не будет работать для пользователей, у которых нет этой версии. (Это может быть то, что вам нужно, если вы не сделали свой код совместимым с Python 2).
  • Нет способа сказать «Python X.Y или новее», поэтому будьте внимательны, используя точную версию, например «/usr/bin/env python3.4», поскольку вам потребуется изменить вашу строку shebang для пользователей Python 3.5, например.

Как правило, вам следует использовать «/usr/bin/env python2» или «/usr/bin/env python3», в зависимости от того, для Python 2 или 3 написан ваш код.

END_OF_DOCUMENT_MARKER ```

Создание автономных приложений с помощью zipapp

Используя модуль zipapp, можно создавать автономные программы Python, которые можно распространять конечным пользователям, которым требуется только подходящая версия Python на их системе. Ключ к этому заключается в объединении всех зависимостей приложения в архив вместе с кодом приложения.

Шаги по созданию автономного архива:

  1. Создайте ваше приложение в каталоге, как обычно, так что у вас есть каталог myapp содержащий файл __main__.py и любой поддерживающий код приложения.
  2. Установите все зависимости вашего приложения в каталог myapp с помощью pip:

    $ python -m pip install -r requirements.txt --target myapp
    

    (это предполагает, что у вас есть требования к проекту в файле requirements.txt — если нет, вы можете просто перечислить зависимости вручную в командной строке pip).

  3. Необязательно, удалите каталоги .dist-info созданные pip в каталоге myapp. Они содержат метаданные для управления пакетами pip, и поскольку вы больше не будете использовать pip, они не требуются — хотя это не навредит, если вы их оставите.
  4. Упакуйте приложение с помощью:

    $ python -m zipapp -p "interpreter" myapp
    

Это создаст автономный исполняемый файл, который можно запустить на любой машине с доступным интерпретатором. Подробности см. в разделе Указание интерпретатора. Его можно отправить пользователям в виде одного файла.

В Unix файле myapp.pyz есть атрибут разрешения на выполнение. Вы можете переименовать файл, удалив расширение .pyz, если предпочитаете простое имя команды. В Windows файл myapp.pyz[w] является исполняемым благодаря тому, что интерпретатор Python регистрирует расширения файлов .pyz и .pyzw при установке.

Создание исполняемого файла для Windows

В Windows регистрация расширения .pyz необязательна, и более того, некоторые места не распознают зарегистрированные расширения «прозрачно» (самый простой пример в том, что subprocess.run(['myapp']) не найдет ваше приложение — вам необходимо явно указать расширение).

Поэтому в Windows часто предпочтительно создавать исполняемый файл из zipapp. Это относительно легко, хотя это требует компилятора C. Основной подход основан на том, что zip-файлы могут иметь произвольные данные в начале, а файлы exe Windows могут иметь произвольные данные в конце. Таким образом, создав подходящий загрузчик и добавив файл .pyz в конец, вы получите исполняемый файл в одном файле, который запустит ваше приложение.

Подходящий загрузчик может быть таким простым:

#define Py_LIMITED_API 1
#include "Python.h"

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#ifdef WINDOWS
int WINAPI wWinMain(
    HINSTANCE hInstance,      /* handle to current instance */
    HINSTANCE hPrevInstance,  /* handle to previous instance */
    LPWSTR lpCmdLine,         /* pointer to command line */
    int nCmdShow              /* show state of window */
)
#else
int wmain()
#endif
{
    wchar_t **myargv = _alloca((__argc + 1) * sizeof(wchar_t*));
    myargv[0] = __wargv[0];
    memcpy(myargv + 1, __wargv, __argc * sizeof(wchar_t *));
    return Py_Main(__argc+1, myargv);
}

Если вы определите препроцессорную переменную WINDOWS, это сгенерирует графический исполняемый файл, а без неё — консольный.

Для компиляции исполняемого файла можно использовать стандартные инструменты командной строки MSVC или воспользоваться возможностью distutils компилировать исходный код Python:

>>> from distutils.ccompiler import new_compiler
>>> import distutils.sysconfig
>>> import sys
>>> import os
>>> from pathlib import Path

>>> def compile(src):
>>>     src = Path(src)
>>>     cc = new_compiler()
>>>     exe = src.stem
>>>     cc.add_include_dir(distutils.sysconfig.get_python_inc())
>>>     cc.add_library_dir(os.path.join(sys.base_exec_prefix, 'libs'))
>>>     # First the CLI executable
>>>     objs = cc.compile([str(src)])
>>>     cc.link_executable(objs, exe)
>>>     # Now the GUI executable
>>>     cc.define_macro('WINDOWS')
>>>     objs = cc.compile([str(src)])
>>>     cc.link_executable(objs, exe + 'w')

>>> if __name__ == "__main__":
>>>     compile("zastub.c")

Полученный загрузчик использует «ограниченный ABI», поэтому он будет работать без изменений с любой версией Python 3.x. Всё, что ему нужно, — это Python (python3.dll) в переменной среды PATH пользователя.

Для полностью автономного дистрибутива вы можете распространять загрузчик с прикрепленным приложением, объединённым с встроенным дистрибутивом Python. Это будет работать на любом ПК с соответствующей архитектурой (32-разрядной или 64-разрядной).

Ограничения

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

  1. Если ваше приложение зависит от пакета, который включает расширение C, этот пакет не может быть запущен из zip-файла (это ограничение ОС, так как исполняемый код должен присутствовать в файловой системе, чтобы загрузчик ОС его загрузил). В этом случае вы можете исключить эту зависимость из zip-файла и либо потребовать, чтобы пользователи её установили, либо распространить её вместе с zip-файлом и добавить код в __main__.py для добавления каталога, содержащего распакованный модуль, в sys.path. В этом случае вам необходимо убедиться, что вы распространяете соответствующие двоичные файлы для ваших целевых архитектур (и, возможно, выбираете правильную версию для добавления в sys.path во время выполнения, в зависимости от машины пользователя).
  2. Если вы распространяете исполняемый файл Windows, как описано выше, вам нужно либо убедиться, что у ваших пользователей python3.dll есть в переменной среды PATH (что не является стандартным поведением установщика), либо вы должны распространять ваше приложение с встроенным дистрибутивом.
  3. Предложенный загрузчик использует API встраивания Python. Это означает, что в вашем приложении sys.executable будет вашим приложением, а не обычным интерпретатором Python. Ваш код и его зависимости должны быть подготовлены к этой возможности. Например, если ваше приложение использует модуль multiprocessing, ему потребуется вызвать multiprocessing.set_executable(), чтобы сообщить модулю, где найти стандартный интерпретатор Python.

Формат архива Python Zip Application

Python может запускать zip-файлы, содержащие файл __main__.py с версии 2.6. Для запуска Python приложение архива должно быть стандартным zip-файлом, содержащим файл __main__.py, который будет выполняться как точка входа приложения. Как обычно для любого скрипта Python, родитель скрипта (в данном случае zip-архив) будет размещен в sys.path и, следовательно, дальнейшие модули могут быть импортированы из zip-файла.

Формат zip-файла позволяет добавлять произвольные данные в начало zip-файла. Формат zip-архива приложения использует эту возможность для добавления стандартной строки shebang POSIX в файл (#!/path/to/interpreter).

Формально, формат Python zip application:

  1. Необязательная строка shebang, содержащая символы b'#!' за которыми следует имя интерпретатора и затем символ новой строки (b'\n'). Имя интерпретатора может быть любым, приемлемым для обработки строки shebang ОС или загрузчика Python в Windows. Имя интерпретатора должно быть закодировано в UTF-8 в Windows и в sys.getfilesystemencoding() в POSIX.
  2. Стандартные данные zip-файла, сгенерированные модулем zipfile. Содержимое zip-файла должно включать файл под названием __main__.py (который должен быть в «корне» zip-файла — то есть, он не может быть в подкаталоге). Содержимое zip-файла может быть сжато или несжато.

Если у архива приложения есть строка shebang, то на системах POSIX может быть установлен атрибут разрешения на выполнение, чтобы позволить выполнить его напрямую.

Нет необходимости использовать инструменты из этого модуля для создания архивов приложений — модуль является удобством, но архивы в указанном выше формате, созданные любым способом, приемлемы для Python.

© 2001–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.9/library/zipapp.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API