|
| 1 | +:mod:`zipapp` --- Manage executable python zip archives |
| 2 | +======================================================= |
| 3 | + |
| 4 | +.. module:: zipapp |
| 5 | + :synopsis: Manage executable python zip archives |
| 6 | + |
| 7 | + |
| 8 | +.. index:: |
| 9 | + single: Executable Zip Files |
| 10 | + |
| 11 | +.. versionadded:: 3.5 |
| 12 | + |
| 13 | +**Source code:** :source:`Lib/zipapp.py` |
| 14 | + |
| 15 | +-------------- |
| 16 | + |
| 17 | +This module provides tools to manage the creation of zip files containing |
| 18 | +Python code, which can be :ref:`executed directly by the Python interpreter |
| 19 | +<using-on-interface-options>`. The module provides both a |
| 20 | +:ref:`zipapp-command-line-interface` and a :ref:`zipapp-python-api`. |
| 21 | + |
| 22 | + |
| 23 | +Basic Example |
| 24 | +------------- |
| 25 | + |
| 26 | +The following example shows how the :ref:`command-line-interface` |
| 27 | +can be used to create an executable archive from a directory containing |
| 28 | +Python code. When run, the archive will execute the ``main`` function from |
| 29 | +the module ``myapp`` in the archive. |
| 30 | + |
| 31 | +.. code-block:: sh |
| 32 | +
|
| 33 | + $ python -m zipapp myapp -m "myapp:main" |
| 34 | + $ python myapp.pyz |
| 35 | + <output from myapp> |
| 36 | +
|
| 37 | +
|
| 38 | +.. _zipapp-command-line-interface: |
| 39 | + |
| 40 | +Command-Line Interface |
| 41 | +---------------------- |
| 42 | + |
| 43 | +When called as a program from the command line, the following form is used: |
| 44 | + |
| 45 | +.. code-block:: sh |
| 46 | +
|
| 47 | + $ python -m zipapp source [options] |
| 48 | +
|
| 49 | +If *source* is a directory, this will create an archive from the contents of |
| 50 | +*source*. If *source* is a file, it should be an archive, and it will be |
| 51 | +copied to the target archive (or the contents of its shebang line will be |
| 52 | +displayed if the --info option is specified). |
| 53 | + |
| 54 | +The following options are understood: |
| 55 | + |
| 56 | +.. program:: zipapp |
| 57 | + |
| 58 | +.. cmdoption:: -o <output>, --output=<output> |
| 59 | + |
| 60 | + Write the output to a file named *output*. If this option is not specified, |
| 61 | + the output filename will be the same as the input *source*, with the |
| 62 | + extension ``.pyz`` added. If an explicit filename is given, it is used as |
| 63 | + is (so a ``.pyz`` extension should be included if required). |
| 64 | + |
| 65 | + An output filename must be specified if the *source* is an archive (and in |
| 66 | + that case, *output* must not be the same as *source*). |
| 67 | + |
| 68 | +.. cmdoption:: -p <interpreter>, --python=<interpreter> |
| 69 | + |
| 70 | + Add a ``#!`` line to the archive specifying *interpreter* as the command |
| 71 | + to run. Also, on POSIX, make the archive executable. The default is to |
| 72 | + write no ``#!`` line, and not make the file executable. |
| 73 | + |
| 74 | +.. cmdoption:: -m <mainfn>, --main=<mainfn> |
| 75 | + |
| 76 | + Write a ``__main__.py`` file to the archive that executes *mainfn*. The |
| 77 | + *mainfn* argument should have the form "pkg.mod:fn", where "pkg.mod" is a |
| 78 | + package/module in the archive, and "fn" is a callable in the given module. |
| 79 | + The ``__main__.py`` file will execute that callable. |
| 80 | + |
| 81 | + :option:`--main` cannot be specified when copying an archive. |
| 82 | + |
| 83 | +.. cmdoption:: --info |
| 84 | + |
| 85 | + Display the interpreter embedded in the archive, for diagnostic purposes. In |
| 86 | + this case, any other options are ignored and SOURCE must be an archive, not a |
| 87 | + directory. |
| 88 | + |
| 89 | +.. cmdoption:: -h, --help |
| 90 | + |
| 91 | + Print a short usage message and exit. |
| 92 | + |
| 93 | + |
| 94 | +.. _zipapp-python-api: |
| 95 | + |
| 96 | +Python API |
| 97 | +---------- |
| 98 | + |
| 99 | +The module defines two convenience functions: |
| 100 | + |
| 101 | + |
| 102 | +.. function:: create_archive(source, target=None, interpreter=None, main=None) |
| 103 | + |
| 104 | + Create an application archive from *source*. The source can be any |
| 105 | + of the following: |
| 106 | + |
| 107 | + * The name of a directory, in which case a new application archive |
| 108 | + will be created from the content of that directory. |
| 109 | + * The name of an existing application archive file, in which case the file is |
| 110 | + copied to the target (modifying it to reflect the value given for the |
| 111 | + *interpreter* argument). The file name should include the ``.pyz`` |
| 112 | + extension, if required. |
| 113 | + * A file object open for reading in bytes mode. The content of the |
| 114 | + file should be an application archive, and the file object is |
| 115 | + assumed to be positioned at the start of the archive. |
| 116 | + |
| 117 | + The *target* argument determines where the resulting archive will be |
| 118 | + written: |
| 119 | + |
| 120 | + * If it is the name of a file, the archive will be written to that |
| 121 | + file. |
| 122 | + * If it is an open file object, the archive will be written to that |
| 123 | + file object, which must be open for writing in bytes mode. |
| 124 | + * If the target is omitted (or None), the source must be a directory |
| 125 | + and the target will be a file with the same name as the source, with |
| 126 | + a ``.pyz`` extension added. |
| 127 | + |
| 128 | + The *interpreter* argument specifies the name of the Python |
| 129 | + interpreter with which the archive will be executed. It is written as |
| 130 | + a "shebang" line at the start of the archive. On POSIX, this will be |
| 131 | + interpreted by the OS, and on Windows it will be handled by the Python |
| 132 | + launcher. Omitting the *interpreter* results in no shebang line being |
| 133 | + written. If an interpreter is specified, and the target is a |
| 134 | + filename, the executable bit of the target file will be set. |
| 135 | + |
| 136 | + The *main* argument specifies the name of a callable which will be |
| 137 | + used as the main program for the archive. It can only be specified if |
| 138 | + the source is a directory, and the source does not already contain a |
| 139 | + ``__main__.py`` file. The *main* argument should take the form |
| 140 | + "pkg.module:callable" and the archive will be run by importing |
| 141 | + "pkg.module" and executing the given callable with no arguments. It |
| 142 | + is an error to omit *main* if the source is a directory and does not |
| 143 | + contain a ``__main__.py`` file, as otherwise the resulting archive |
| 144 | + would not be executable. |
| 145 | + |
| 146 | + If a file object is specified for *source* or *target*, it is the |
| 147 | + caller's responsibility to close it after calling create_archive. |
| 148 | + |
| 149 | + When copying an existing archive, file objects supplied only need |
| 150 | + ``read`` and ``readline``, or ``write`` methods. When creating an |
| 151 | + archive from a directory, if the target is a file object it will be |
| 152 | + passed to the ``zipfile.ZipFile`` class, and must supply the methods |
| 153 | + needed by that class. |
| 154 | + |
| 155 | +.. function:: get_interpreter(archive) |
| 156 | + |
| 157 | + Return the interpreter specified in the ``#!`` line at the start of the |
| 158 | + archive. If there is no ``#!`` line, return :const:`None`. |
| 159 | + The *archive* argument can be a filename or a file-like object open |
| 160 | + for reading in bytes mode. It is assumed to be at the start of the archive. |
| 161 | + |
| 162 | + |
| 163 | +.. _zipapp-examples: |
| 164 | + |
| 165 | +Examples |
| 166 | +-------- |
| 167 | + |
| 168 | +Pack up a directory into an archive, and run it. |
| 169 | + |
| 170 | +.. code-block:: sh |
| 171 | +
|
| 172 | + $ python -m zipapp myapp |
| 173 | + $ python myapp.pyz |
| 174 | + <output from myapp> |
| 175 | +
|
| 176 | +The same can be done using the :func:`create_archive` functon:: |
| 177 | + |
| 178 | + >>> import zipapp |
| 179 | + >>> zipapp.create_archive('myapp.pyz', 'myapp') |
| 180 | + |
| 181 | +To make the application directly executable on POSIX, specify an interpreter |
| 182 | +to use. |
| 183 | + |
| 184 | +.. code-block:: sh |
| 185 | +
|
| 186 | + $ python -m zipapp myapp -p "/usr/bin/env python" |
| 187 | + $ ./myapp.pyz |
| 188 | + <output from myapp> |
| 189 | +
|
| 190 | +To replace the shebang line on an existing archive, create a modified archive |
| 191 | +using the :func:`create_archive` function:: |
| 192 | + |
| 193 | + >>> import zipapp |
| 194 | + >>> zipapp.create_archive('old_archive.pyz', 'new_archive.pyz', '/usr/bin/python3') |
| 195 | + |
| 196 | +To update the file in place, do the replacement in memory using a :class:`BytesIO` |
| 197 | +object, and then overwrite the source afterwards. Note that there is a risk |
| 198 | +when overwriting a file in place that an error will result in the loss of |
| 199 | +the original file. This code does not protect against such errors, but |
| 200 | +production code should do so. Also, this method will only work if the archive |
| 201 | +fits in memory:: |
| 202 | + |
| 203 | + >>> import zipapp |
| 204 | + >>> import io |
| 205 | + >>> temp = io.BytesIO() |
| 206 | + >>> zipapp.create_archive('myapp.pyz', temp, '/usr/bin/python2') |
| 207 | + >>> with open('myapp.pyz', 'wb') as f: |
| 208 | + >>> f.write(temp.getvalue()) |
| 209 | + |
| 210 | +Note that if you specify an interpreter and then distribute your application |
| 211 | +archive, you need to ensure that the interpreter used is portable. The Python |
| 212 | +launcher for Windows supports most common forms of POSIX ``#!`` line, but there |
| 213 | +are other issues to consider: |
| 214 | + |
| 215 | +* If you use "/usr/bin/env python" (or other forms of the "python" command, |
| 216 | + such as "/usr/bin/python"), you need to consider that your users may have |
| 217 | + either Python 2 or Python 3 as their default, and write your code to work |
| 218 | + under both versions. |
| 219 | +* If you use an explicit version, for example "/usr/bin/env python3" your |
| 220 | + application will not work for users who do not have that version. (This |
| 221 | + may be what you want if you have not made your code Python 2 compatible). |
| 222 | +* There is no way to say "python X.Y or later", so be careful of using an |
| 223 | + exact version like "/usr/bin/env python3.4" as you will need to change your |
| 224 | + shebang line for users of Python 3.5, for example. |
| 225 | + |
| 226 | +The Python Zip Application Archive Format |
| 227 | +----------------------------------------- |
| 228 | + |
| 229 | +Python has been able to execute zip files which contain a ``__main__.py`` file |
| 230 | +since version 2.6. In order to be executed by Python, an application archive |
| 231 | +simply has to be a standard zip file containing a ``__main__.py`` file which |
| 232 | +will be run as the entry point for the application. As usual for any Python |
| 233 | +script, the parent of the script (in this case the zip file) will be placed on |
| 234 | +:data:`sys.path` and thus further modules can be imported from the zip file. |
| 235 | + |
| 236 | +The zip file format allows arbitrary data to be prepended to a zip file. The |
| 237 | +zip application format uses this ability to prepend a standard POSIX "shebang" |
| 238 | +line to the file (``#!/path/to/interpreter``). |
| 239 | + |
| 240 | +Formally, the Python zip application format is therefore: |
| 241 | + |
| 242 | +1. An optional shebang line, containing the characters ``b'#!'`` followed by an |
| 243 | + interpreter name, and then a newline (``b'\n'``) character. The interpreter |
| 244 | + name can be anything acceptable to the OS "shebang" processing, or the Python |
| 245 | + launcher on Windows. The interpreter should be encoded in UTF-8 on Windows, |
| 246 | + and in :func:`sys.getfilesystemencoding()` on POSIX. |
| 247 | +2. Standard zipfile data, as generated by the :mod:`zipfile` module. The |
| 248 | + zipfile content *must* include a file called ``__main__.py`` (which must be |
| 249 | + in the "root" of the zipfile - i.e., it cannot be in a subdirectory). The |
| 250 | + zipfile data can be compressed or uncompressed. |
| 251 | + |
| 252 | +If an application archive has a shebang line, it may have the executable bit set |
| 253 | +on POSIX systems, to allow it to be executed directly. |
| 254 | + |
| 255 | +There is no requirement that the tools in this module are used to create |
| 256 | +application archives - the module is a convenience, but archives in the above |
| 257 | +format created by any means are acceptable to Python. |
0 commit comments