So, you've created a Python app (be it a graphical user interface with Qt or the like, or a simple command line interface). Great! But how are others going to use it? Python applications often have dependencies (e.g. from third-party modules), and they also need a Python interpreter to run them. For a developer, installing all the necessary bits and bobs to make things work is okay, but that's unacceptable for a normal user - they just want to download the thing and run it.
Below are simple instructions to publish your app on the three main operating systems: Windows, macOS and Linux.
Windows users expect to download installers from random websites.
Users on macOS can deal with downloading a random .app file and dragging it into their Applications directory, because publishing on the App Store is a nuisance.
To remove the requirement of installing Python on the user's computer, we'll just bundle the entire interpreter with the app. Use some sort of freezing utility to do this; in this tutorial, cx_Freeze will be used. Note that frozen apps can only be run on the platform they were created on: if you freeze your app on Windows, it'll only run on Windows; same applies for macOS.
- Open a terminal.
- Install cx_Freeze with
pip install cx_freeze
.
You might need to usesudo
or--user
if you're on macOS. - Generate a setup.py file with
cxfreeze-quickstart
, and edit it to your liking (for example, to add an icon). - If you're on Windows, create the installer for your app with
python ./setup.py bdist_msi
.
If you're on macOS, create the .app withpython ./setup.py bdist_mac
. - Host your file somewhere, like GitHub.
Check out https://cx-freeze.readthedocs.io/en/latest/faq.html if you have any problems.
On Linux, you can just package the .py script itself (preferably) for distro-specific formats, or on all distros with distro-agnostic tools like pip itself (since Linux distros often already have pip and Python installed), AppImages, snaps or Flatpaks. However, in the case of Flatpaks and snaps, your users will need to install the packaging system (which defeats the whole purpose of packaging with dependencies...)
The Arch Wiki is your friend.
- Create a setup.py.
- Create a PKGBUILD.
See https://wiki.archlinux.org/index.php/Python_package_guidelines for Python specifics. - Create an AUR account.
- Submit your package.
Users will install manually or with an AUR helper through the terminal.
- Create a setup.py.
- Create an RPM package with
./setup.py bdist_rpm
. - Extract the RPM with
rpm2cpio dist/RPMFILENAMEHERE.rpm | cpio -idmv
and edit the specfile inside SPECS if necessary (e.g. to include external, non-Python dependencies).
Note that you'll need to install rpm2cpio and cpio if they're not already installed. Afterwards, rebuild withrpmbuild -ba SPECS/SPECNAMEHERE.spec
. - Host it somewhere, or use COPR.
This and this may be good tutorials.
This method assumes your user has (the right version of) Python installed. The guide is based on https://packaging.python.org/tutorials/distributing-packages/#packaging-your-project.
- Create a setup.py.
- Create a "source distribution" with
./setup.py sdist
. - Install wheel to create more efficient packages with
sudo pip install wheel
. - Generate the more efficient package, known as a "wheel", with
./setup.py bdist_wheel
.
If your code runs fine on both Python 2 and 3 without any C extensions, include the--universal
argument. - Create a PyPI account to upload your package.
- Install twine to upload your package with
sudo pip install twine
. - Finally, upload it with
twine upload dist/*
.
To install the package, users can run pip install --user
with your package's name.
Here are instructions and commands on how to make one for Python apps, duplicated for simplicity below.
- Install virtualenv.
- Download some helper functions with
wget -q https://github.com/probonopd/AppImages/raw/master/functions.sh -O ./functions.sh
. - Source the helper functions with
. ./functions.sh
. - Set variables for later:
APP=APPNAMEHERE; LOWERAPP=${APP,,}
, replacing APPNAMEHERE with your Python script's name. - Create the package directory with
mkdir -p $APP/$APP.AppDir/usr/bin/
. - Enter the directory with
cd $APP/$APP.AppDir
. - Create a virtualenv for the dependencies with
virtualenv usr
. - Install your app's third-party module dependencies using
pip install
followed by the module names. - Save your Python script in usr/bin.
- Grant it execution permissions with
chmod a+x usr/bin/$LOWERAPP
. - Prepare to finalise with
get_apprun
. - Maybe create a desktop entry.
- Install with
get_desktopintegration $LOWERAPP
. - Add an icon image to $LOWERAPP.png.
- Bundle dependencies with
copy_deps; copy_deps; copy_deps
. - Finalise finalisation with
delete_blacklisted; move_lib
. - Set the version number with
VERSION=
followed by your version number. - Test that it works with
./AppRun
. - Get out of the dir to prepare to create an AppImage with
cd ..
. - Finally, generate the AppImage with
generate_appimage
. - Host the file somewhere for users to download and click-to-run.
For Python snaps, see this example and this tutorial.
- Install snapd using your distro's package manager.
- Create a setup.py that states the third-party module dependencies.
- Create a new directory for the snap with
mkdir SOME_DIR
. - Initialise it as a snap with
snapcraft init
, and edit the resulting snap/snapcraft.yaml file. - You may also want to create a .desktop file (if your app has a GUI) in a meta/gui directory, so users can launch it from their desktop environment.
- Create an Ubuntu account to publish the snap.
- Log in with
snapcraft login
. - Reserve the package name with
snapcraft register PACKAGE_NAME
. - Upload the snap with
snapcraft push --release=[edge or stable] PACKAGE_NAME_*.snap
.
Users will install it with snap install PACKAGE_NAME
, and run it with COMMAND_NAME
.
Here is the Flatpak documentation.
- Install flatpak and flatpak-builder with your package manager.
- Install a runtime and SDK for the flatpak. For this example, we'll be using the org.gnome.Sdk SDK and org.gnome.Platform runtime.
- Initialise a flatpak with
flatpak build-init DIRECTORY DBUS_APP_NAME org.gnome.Sdk org.gnome.Platform
. - Create a setup.py.
- Install the script with
flatpak build DIRECTORY ./setup.py install
. - Grant permissions
with
flatpak build-finish DIRECTORY PERMISSIONS --command=COMMAND_NAME
. - Generate a GPG key for hosting.
- Create a base64-encoded key with
base64 --wrap=0 < PACKAGE_NAME.gpg
. - Generate a .flatpakref.
- Create a repo to host the package with
flatpak build-export --gpg-sign=KEYID --gpg-homedir=PATH LOCAL_REPO DIRECTORY; flatpak --user remote-add --if-not-exists REMOTE_REPO LOCAL_REPO
.
Users can install it by downloading the .flatpakref or running flatpak insall --from PACKAGE_NAME.flatpakref
.
Unfortunately, with Flatpaks, using Python is cumbersome: flatpak run --command=python DBUS_APP_NAME --ARGS
.
Hopefully you now know how to package a Python script or graphical program for Windows, macOS and Linux. For Windows, users expect installers; for macOS, .app executables are dragged into a directory or downloaded from the App Store; and for Linux, some sort of command line with the source code is used.