PyInstaller is a program used to convert Python scripts into standalone applications. PyInstaller allows you to run applications written in Python on a computer without requiring the user to install Python. It is an excellent option when you need to distribute a program to the end user as a standalone application. PyInstaller currently only works with Python 2.3 up to 2.7.
PyInstaller claims to be compatible with a lot of third party libraries or packages out of the box. PyQt, Django and matplotlib are fully supported.
To start, download and extract PyInstaller from the official site.
PyInstaller is an application, not a package. So there is no need to install it in your computer. To get started, open a Command Prompt (Windows) or a Terminal (Mac and Linux) and go to the PyInstaller Folder.
cd pyinstaller
Now suppose you want to package myscript.py, I saved it into the pyinstaller folder:
# myscript.py print('Hello World!')
- How to Install Django on Windows, Mac and Linux
- How to Install SQLAlchemy
- Package Your Python Django Application into a Reusable Component
Then, in order to create the executable just run python pyinstaller.py myscript.py
and you will see a lot of output and a folder called myscript
will be created, with two folders and a file inside. The build
folder is used by PyInstaller as a temporary folder to create the files needed for the executable. The dist
folder stores the executable and all of the files needed in order to run that executable. It is safe to delete the build folder. The file called myscript.spec
is useful to customize the way PyInstaller packs your application.
Now test if your executable works:
Windows
cd myscript/dist/myscript myscript
Mac and Linux
cd myscript/dist/myscript ./myscript
You should see now a “Hello World!” printed on the screen.
Remember that running python pyinstaller.py myscript.py
assumes that you have Python in your path environment variable. If that is not the case, just use C:\Python27\python.exe pyinstaller.py myscript.py
in Windows. Most of the time on Linux and Mac OS X, Python will be in your path environment variable.
GUI Applications
Now it is time to create a GUI application. In this example we will be using Tkinter:
# tkexample.py '''A very basic Tkinter example. ''' import Tkinter from Tkinter import * root = Tk() root.title('A Tk Application') Label(text='I am a label').pack(pady=15) root.mainloop()
To pack it, it is mandatory to use the --windowed
flag, otherwise the application will not start:
python pyinstaller.py --windowed tkexample.py
In this moment you can navigate to the dist folder and run the application by double clicking it.
Note for Mac OS X users: the above example using Tkinter works fine if you use the pre-installed Python version, if you installed or updated Python by yourself, you can find some problems running the packaged application.
Using External Modules
The previous examples were importing modules from the Python Standard Library. PyInstaller includes the Standard Library Modules by default. However if we installed a third party library, PyInstaller is likely not to include it. In most of the cases we need to create “hooks” to tell PyInstaller to include these modules. An example of this is an application using the ReportLab library to make PDF files:
# invoice.py from reportlab.pdfgen import canvas from reportlab.lib.pagesizes import letter from reportlab.lib.units import mm if __name__ == '__main__': name = u'Mr. John Doe' city = 'Pereira' address = 'ELM Street' phone = '555-7241' c = canvas.Canvas(filename='invoice.pdf', pagesize= (letter[0], letter[1]/2)) c.setFont('Helvetica', 10) # Print Customer Data c.drawString(107*mm, 120*mm, name) c.drawString(107*mm, 111*mm, city) c.drawString(107*mm, 106*mm, address) c.drawString(107*mm, 101*mm, phone) c.showPage() c.save()
A “hook” module is a Python file with a special name, used to tell PyInstaller to include a specific module. Doing a Google search i found the needed hooks to pack a ReportLab application here and placed them in a folder named “hooks”:
+- hooks/
|- hook-reportlab.pdfbase._fontdata.py
|- hook-reportlab.pdfbase.py
|- hook-reportlab.py
hook-reportlab.py
and hook-reportlab.pdfbase.py
are empty files, hook-reportlab.pdfbase._fontdata.py
contains:
# hook-reportlab.pdfbase._fontdata.py hiddenimports = [ '_fontdata_enc_macexpert', '_fontdata_enc_macroman', '_fontdata_enc_pdfdoc', '_fontdata_enc_standard', '_fontdata_enc_symbol', '_fontdata_enc_winansi', '_fontdata_enc_zapfdingbats', '_fontdata_widths_courier', '_fontdata_widths_courierbold', '_fontdata_widths_courierboldoblique', '_fontdata_widths_courieroblique', '_fontdata_widths_helvetica', '_fontdata_widths_helveticabold', '_fontdata_widths_helveticaboldoblique', '_fontdata_widths_helveticaoblique', '_fontdata_widths_symbol', '_fontdata_widths_timesbold', '_fontdata_widths_timesbolditalic', '_fontdata_widths_timesitalic', '_fontdata_widths_timesroman', '_fontdata_widths_zapfdingbats' ]
Now in order to pack the executable, we have to run python pyinstaller.py --additional-hooks-dir=hooks/ invoice.py
. The additional-hooks-dir
flag tells PyInstaller to search for hooks in the specified directory.
Conclusion
Pyinstaller works great if your script only imports modules from The Python Standard Library, or a module included in the official Supported Packages list. Using these supported packages make packaging applications pretty straightforward, but when wee need to use a third-party not supported module, it can be tricky to make it work.