{# This document describes the usage of the python-appimage utility.
The intended audience is developers. In addition, this document also provides some tips for packaging Python based applications. #}
{{ importjs("highlight.min") }} {{ importjs("apps") }}
{% include "references.md" %}
Python [AppImages][APPIMAGE] are created using the python-appimage utility,
which is available on [PyPI][PYPI]. This utility can also be used to package
Python-based applications as AppImages using an existing AppImage and a recipe
folder.
!!! Caution
The `python-appimage` utility can only package applications that can be
installed directly with `pip`. For more advanced usage, it is necessary to
extract and edit the Python AppImage, as explained in the [Advanced
installation](index.md#advanced-installation) section. Further details on
this use case can be found [below](#advanced-packaging).
The primary purpose of python-appimage is to relocate an existing Python
installation to an AppDir and build the corresponding AppImage. For example, the
command
python-appimage build local -p $(which python2)
should create an AppImage of your local Python installation, provided that it exists.
!!! Tip
Help on the available arguments and options for `python-appimage` can be
obtained by using the `-h` flag. For example, running
`python-appimage build local -h` provides help on local builds.
{{ begin(".capsule") }}
The python-appimage utility relies on auxiliary tools that are downloaded and
installed on demand during application execution. These are
[appimagetool][APPIMAGETOOL], which is used to build AppImages, and
[patchelf][PATCHELF], which is used to edit runtime paths (RPATH) in ELF
files. These auxiliary tools are installed in the application cache. Their
location can be found using the which command. For example, the command
python-appimage which appimagetool
returns the location of [appimagetool][APPIMAGETOOL] if it has been installed.
If not, the install command can be used to trigger its installation.
{{ end(".capsule") }}
AppImages of your local python are unlikely to be portable, unless you are
running an outdated Linux distribution. A core component that prevents
portability across Linux distributions is the use of different versions of the
glibc system library. Fortunately, glibc is highly backward compatible.
Therefore, a simple workaround is to compile binaries using the oldest Linux
distribution you can. This strategy is used to create portable AppImages and to
distribute Python site packages as ready-to-use binary [wheels][WHEELS].
The Python Packaging Authority (PyPA) has defined standard platform tags for
building Python site packages labelled [Manylinux][MANYLINUX]. These build
platforms are available as Docker images, with different versions of Python
already installed. The python-appimage utility can be used to package these
installations as AppImages. For example, the following command
python-appimage build manylinux 2014_x86_64 cp313-cp313
should build an AppImage of Python 3.13 using the CPython (cp313-cp313)
installation found in the manylinux2014_x86_64 Docker image.
!!! Note
From version `1.4.0` of `python-appimage` onwards, Docker is **no longer**
required to build the Manylinux Python images. Cross-building is also
supported, for example producing an `aarch64` Python image from an `x86_64`
host.
!!! Warning
Creating multiple Manylinux Python images can significantly increase the
size of the application cache. This can be managed using the
`python-appimage cache` command.
!!! Tip
A compilation of ready-to-use Manylinux Python AppImages is available in the
[releases][RELEASES] section of the `python-appimage` [GitHub
repository][GITHUB]. These AppImages are updated weekly, on every Sunday.
!!! Tip
Instead of an AppImage, the `python-appimage build manylinux` command can
produce either an `AppDir` or a bare tarball (i.e. without the AppImage
layer) of a Manylinux Python installation. See the `-b` and `-n` command
line options for more information.
The python-appimage utility can also be used to package simple AppImage
applications, whose dependencies can be installed using pip. The syntax is
python-appimage build app -p 3.13 /path/to/recipe/folder
to build a Python 3.13-based application from a recipe folder. Examples of recipes can be found in the [applications][APPLICATIONS] folder on GitHub. The recipe folder contains
application.xml and application.desktop),application.png),requirements.txt),entrypoint.sh).Further information on metadata can be found in the AppImage documentation
(e.g., regarding [desktop][APPIMAGE_DESKTOP] and [AppStream XML][APPIMAGE_XML]
files). The requirements.txt file enables additional site packages to be
specified for bundling in the AppImage using pip.
!!! Caution
In order for the application to be portable, the site packages bundled in
the AppImage and their dependencies must be available as binary wheels or
pure Python packages.
If a **C extension** is bundled from **source**, it will likely **not be
portable**; this is discussed further in the [Advanced
packaging](#advanced-packaging) section.
!!! Tip
Some site packages are only available for specific Manylinux tags. You can
check this by browsing the `Download files` section on the package's PyPI
page.
!!! Tip
Since version 1.2, `python-appimage` allows local requirements to be
specified using the `local+` tag (see
[PR49](https://github.com/niess/python-appimage/pull/49)). Please note,
however, that this involves directly copying the local package, which has
several limitations.
{{ begin(".capsule") }}
{% raw %}
The entry point script deserves some additional explanations. This script lets
you customise your application's startup. A typical entrypoint.sh script would
look like this
{{ python-executable }} ${APPDIR}/opt/python{{ python-version }}/bin/my_app.py "$@"
where my_app.py is the application startup script installed by pip. As can
be seen from the previous example, the entrypoint.sh script recognises
particular variables nested between double curly braces ({{}}). These
variables are listed in the table below. In addition, the usual [AppImage
environement variables][APPIMAGE_ENV] can be used if needed. For instance,
$APPDIR points to the AppImage mount point at runtime.
{% endraw %}
| variable | Description |
|---|---|
architecture |
The AppImage architecture, e.g. x86_64. |
linux-tag |
The Manylinux compatibility tag, e.g. manylinux2014_x86_64. |
python-executable |
Path to the AppImage Python runtime. |
python-fullversion |
The Python full version string, e.g. 3.10.2. |
python-tag |
The Python compatibility tag, e.g. cp310-cp310. |
python-version |
The Python short version string, e.g. 3.10. |
{{ end(".capsule") }}
{% raw %} !!! Note
By default, Python AppImages are not isolated from user space or
Python-specific environment variables such as `PYTHONPATH`. Depending on
your use case, this can cause problems.
You can change the isolation level by adding the `-E`, `-s` or `-I` options
when invoking the runtime. For example, `{{ python-executable }} -I` starts
a fully isolated Python instance.
{% endraw %}
python-appimage is also capable of bundling auxiliary data files directly into
the resulting AppImage. The -x/--extra-data switch is used for this purpose.
Consider the following example.
echo -n "foo" > foo
mkdir bar
echo -n "baz" > bar/baz
python-appimage [your regular parameters] -x foo bar/*
In this way, user data becomes accessible to the Python code contained within
the AppImage as regular files under the directory pointed to by the APPDIR
environment variable. An example of a Python 3 script that reads these files is
presented below.
import os, pathlib
for fileName in ("foo", "baz"):
print((pathlib.Path(os.getenv("APPDIR")) / fileName).read_text())
When executed, the above code would produce the following output.
foo
baz
In more complex cases, for example if your application relies on external C
libraries that are not bundled with the Python runtime, the simple packaging
scheme described previously will not work. This falls outside the scope of
python-appimage, which is primarily intended for relocating an existing Python
installation. In this case, you may wish to refer to the initial AppImage
[Packaging Guide][APPIMAGE_PACKAGING], and use alternative tools such as
[linuxdeploy][LINUXDEPLOY].
However, python-appimage can still be useful in more complex cases, as it can
generate a base AppDir containing a relocatable Python runtime (e.g., using the
-n option). This can then serve as a starting point to create more complex
AppImages.
!!! Tip
In some cases, a simple workaround for missing external libraries is to
download portable versions of them from a Manylinux distribution and bundle
them in `AppDir/usr/lib`. You may also need to edit the dynamic section
using [`patchelf`][PATCHELF], which is installed by `python-appimage`.
{{ begin(".capsule") }}
If your application relies on C extension modules, these must be compiled on a
Manylinux distribution in order to be portable. Their dependencies also need to
be bundled. In this case, it would be better to start by building a binary wheel
of your package using tools like [Auditwheel][AUDITWHEEL], which can automate
some parts of the packaging process. Please note that auditwheel is already
installed on the Manylinux Docker images.
Once you have built a binary wheel of your package, you can use it with
python-appimage to package your application as an AppImage.
{{ end(".capsule") }}