Spec-Zone.ru › Python 3.8

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>

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

-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 должен быть каталогом, и целевой файл будет иметь такое же имя, как source, с добавленным расширением .pyz.

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

Аргумент main указывает имя вызываемого элемента, который будет использоваться в качестве основной программы для архива. Он может быть указан только в том случае, если source — это каталог, и исходный каталог уже не содержит файл __main__.py. Аргумент main должен иметь вид «pkg.module:callable», и архив будет выполнен путем импорта «pkg.module» и выполнения указанного вызываемого элемента без аргументов. Ошибка — опустить main, если source — каталог и он не содержит файл __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 поддерживает большинство распространенных форм строки shebang 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 написан ваш код.

Создание автономных приложений с помощью 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.8/library/zipapp.html

Spec-Zone.ru

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