Building stand-alone command line tools using Python
You have built a neat little tool using Python. Following modern software building paradigms, you built your tool to be user friendly, used a number of FOSS libraries instead of reinventing the wheel, etc. Now you are ready to ship and you face the dilemma of whether to package it as a conda package or PyPI package or whether to send it as a GitHub repository. What if your user does not want to even install Python on their computer?
Fear not, you can build truly self-contained stand-alone applications using PyInstaller. The rest of this blog walks you through an example.
What is PyInstaller
From PyInstaller's page: PyInstaller bundles a Python application and all its dependencies into a single package. The user can run the packaged app without installing a Python interpreter or any modules. PyInstaller supports Python 2.7 and Python 3.3+, and correctly bundles the major Python packages such as numpy, PyQt, Django, wxPython, and others. PyInstaller is tested against Windows, Mac OS X, and Linux.
How to install PyInstaller
Before using PyInstaller, you need to install it in your active Python environment. If you are not already using, I would highly recommend using
conda to isolate your various dev environments. You can install conda from here and once installed, you can create a new environment using the command below:
conda create --name stand_alone_app_project python=3.5
Here, I am creating a new environment called
stand_alone_app_project and installing a Python 3.5 kernel in it. To use this environment, I need to activate it - as shown below
source activate stand_alone_app_project
Environments are folders at the end of the day and activation pretty much adds the path to this folder to your system path. Activation is transient and is only applicable for the life of that terminal's session. Once activated, install all the packages you need for your script to work. Next, install PyInstaller using PIP (an older package manager for Python)
pip install PyInstaller
Building stand-alone applications.
PyInstaller allows you to create apps in two formats - as folder with dependencies and an application or option 2 - is to create a fully packaged single executable file. I prefer the latter as it resembles closely what my end users would want and also allows to run the tool from a flash drive, without any installation. In both cases, you will package a Python runtime and all dependencies.
To build an app and package it into a folder, run
To build it as a single file executable, run
pyinstaller your_main_script.py --onefile
Upon running this, if there are no errors, PyInstaller creates a
dist and a
build folder. You ship the contents of the
dist to your end users.
Building for different OS
To build the executable for different OS, you need to run the steps on each OS of choice. I was able to build the same script tool into a Windows
exe and a Unix
app for Mac. Since Python is platform independent, doing this was a breeze and the app behaved identical on both platforms.
Errors and what to do
Your first few times with PyInstaller will be rough. You will run into errors unless you are packaging a
hello world.py kind of script. In my case, I was packaging a tool that relied on
requests package and PyInstaller could not understand this package. After a brief search on Stack Exchange, I was able to figure out that I needed to install
urllib3 on Mac to get it working. Similarly, on Windows, I needed to install
pypiwin32. The latter is true no matter what package you use.
Although PyInstaller aims to recursively parse the
import statements in your script and all its dependencies to figure out the libraries to package, it might fall short if you are using irregular imports. In such cases, read their appropriately named When things go wrong article.
Conda and Pip are excellent mechanisms to ship your Python code. Yet, they are suitable if you are building libraries and your audience is fellow developers. However, if you are creating an application for end users, then you need to ship it as an executable. Python still falls short in this area compared to other languages like C++, Java, .NET. We are yet to find an IDE that will build your script into an executable (similar to what visual studio does out of the box since ages). Tools like py2exe and PyInstaller are great as they attempt to solve this gap. Yet, this is only the beginning and I am sure the Python community would greatly benefit if we can expand this area.
If you are looking for an example project, checkout my command line app at https://github.com/AtmaMani/vector_style_manager