zipapp — Керування виконуваними zip-архівами Python

Added in version 3.5.

Вихідний код: Lib/zipapp.py


Цей модуль надає інструменти для керування створенням zip-файлів, що містять код Python, який можна виконувати безпосередньо інтерпретатором Python. Модуль забезпечує як Інтерфейс командного рядка, так і API Python.

Базовий приклад

У наступному прикладі показано, як Інтерфейс командного рядка можна використовувати для створення виконуваного архіву з каталогу, що містить код Python. Під час запуску архів виконає функцію main з модуля myapp в архіві.

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

Інтерфейс командного рядка

При виклику програми з командного рядка використовується така форма:

$ python -m zipapp source [options]

Якщо source є каталогом, буде створено архів із вмісту source. Якщо джерело є файлом, це має бути архів, і його буде скопійовано до цільового архіву (або буде показано вміст його рядка shebang, якщо вказано параметр –info).

Розуміються такі варіанти:

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

Запишіть вихідні дані у файл з назвою output. Якщо цей параметр не вказано, ім’я вихідного файлу буде таким самим, як і вхідне джерело, із доданим розширенням .pyz. Якщо вказано явне ім’я файлу, воно використовується як є (тому за потреби слід включити розширення .pyz).

Необхідно вказати ім’я вихідного файлу, якщо джерело є архівом (і в такому випадку вихід не має збігатися з джерелом).

-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 не діє під час копіювання архіву.

Added in version 3.7.

--info

Відобразити інтерпретатор, вбудований в архів, для діагностичних цілей. У цьому випадку будь-які інші параметри ігноруються, а SOURCE має бути архівом, а не каталогом.

-h, --help

Надрукуйте коротке повідомлення про використання та вийдіть.

API Python

Модуль визначає дві функції зручності:

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

Створіть архів програми з джерела. Джерелом може бути будь-яке з наступного:

  • Ім’я каталогу або path-like object, що посилається на каталог, у цьому випадку новий архів програми буде створено з вмісту цього каталогу.

  • Ім’я існуючого архівного файлу програми або path-like object, що посилається на такий файл, у такому випадку файл копіюється в ціль (з його зміною, щоб відобразити значення, задане для аргументу interpreter ). Якщо потрібно, ім’я файлу має містити розширення .pyz.

  • Файловий об’єкт, відкритий для читання в байтовому режимі. Вмістом файлу має бути архів програми, а об’єкт файлу має бути розташований на початку архіву.

Аргумент target визначає, куди буде записаний отриманий архів:

  • Якщо це ім’я файлу або path-like object, архів буде записаний у цей файл.

  • Якщо це відкритий файловий об’єкт, архів буде записаний у цей файловий об’єкт, який має бути відкритим для запису в байтовому режимі.

  • Якщо ціль пропущено (або None), джерело має бути каталогом, а ціль буде файлом із такою самою назвою, як і джерело, із доданим розширенням .pyz.

Аргумент інтерпретатор визначає ім’я інтерпретатора Python, за допомогою якого буде виконуватися архів. Він записується як рядок «shebang» на початку архіву. У POSIX це буде інтерпретовано ОС, а в Windows це оброблятиметься програмою запуску Python. Пропуск інтерпретатора призводить до того, що рядок shebang не записується. Якщо вказано інтерпретатор, а метою є ім’я файлу, буде встановлено виконуваний біт цільового файлу.

Аргумент main вказує назву викликаної програми, яка буде використана як основна програма для архіву. Його можна вказати, лише якщо джерелом є каталог, і джерело ще не містить файл __main__.py. Аргумент main має мати вигляд «pkg.module:callable», і архів буде запущено шляхом імпорту «pkg.module» і виконання заданого callable без аргументів. Пропускати main буде помилкою, якщо джерело є каталогом і не містить файлу __main__.py, інакше отриманий архів не буде виконуваним.

Необов’язковий аргумент filter визначає функцію зворотного виклику, якій передається об’єкт Path, що представляє шлях до доданого файлу (відносно вихідного каталогу). Він має повернути True, якщо файл потрібно додати.

Додатковий аргумент compressed визначає, чи стискаються файли. Якщо встановлено значення True, файли в архіві стискаються за допомогою методу deflate; інакше файли зберігаються нестисненими. Цей аргумент не діє під час копіювання існуючого архіву.

Якщо для source або target указано файловий об’єкт, закрити його після виклику create_archive несе абонент, що викликає.

Під час копіювання існуючого архіву наданим файловим об’єктам потрібні лише методи read і readline або write. Під час створення архіву з каталогу, якщо метою є файловий об’єкт, він буде переданий до класу zipfile.ZipFile і повинен надати методи, необхідні цьому класу.

Змінено в версії 3.7: Added the filter and compressed parameters.

zipapp.get_interpreter(archive)

Повертає інтерпретатор, указаний у рядку #! на початку архіву. Якщо рядка #! немає, поверніть 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')

To update the file in place, do the replacement in memory using a BytesIO object, and then overwrite the source afterwards. Note that there is a risk when overwriting a file in place that an error will result in the loss of the original file. This code does not protect against such errors, but production code should do so. Also, this method will only work if the archive fits in memory:

>>> 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.

Створення автономних програм за допомогою zipap

Використовуючи модуль zipapp, можна створювати самодостатні програми Python, які можна розповсюджувати серед кінцевих користувачів, яким потрібно лише встановити відповідну версію Python у своїй системі. Ключ до цього полягає в тому, щоб об’єднати всі залежності програми в архів разом із кодом програми.

Щоб створити окремий архів, виконайте наведені нижче дії.

  1. Створіть свою програму в каталозі як зазвичай, щоб у вас був каталог myapp, що містить файл __main__.py і будь-який допоміжний код програми.

  2. Встановіть усі залежності вашої програми в каталог myapp за допомогою pip:

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

    (це припускає, що у вас є вимоги до проекту у файлі requirements.txt - якщо ні, ви можете просто вручну перерахувати залежності в командному рядку pip).

  3. Упакуйте програму за допомогою:

    $ python -m zipapp -p "interpreter" myapp
    

Це створить окремий виконуваний файл, який можна буде запустити на будь-якій машині з доступним відповідним інтерпретатором. Дивіться Вказівка Інтерпретатора для деталей. Його можна надіслати користувачам як один файл.

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

Застереження

Якщо ваша програма залежить від пакета, який містить розширення C, цей пакет не можна запустити з zip-файлу (це обмеження ОС, оскільки виконуваний код має бути присутнім у файловій системі, щоб завантажувач ОС міг його завантажити). У цьому випадку ви можете виключити цю залежність із zip-файлу та вимагати, щоб ваші користувачі встановили його, або надіслати його разом із zip-файлом і додати код до свого __main__.py, щоб включити каталог, що містить розархівований модуль, у sys.path. У цьому випадку вам потрібно буде переконатися, що надіслано відповідні двійкові файли для вашої цільової архітектури (і, можливо, вибрати правильну версію для додавання до sys.path під час виконання, на основі комп’ютера користувача).

Формат архіву програми Python Zip

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

Формат файлу zip дозволяє додавати довільні дані до файлу zip. Формат програми zip використовує цю можливість для додавання до файлу стандартного рядка POSIX «shebang» (#!/path/to/interpreter).

Формально формат програми Python zip є таким:

  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.