It can’t surely be that simple? Can it? What if I need to…

Bundle Libraries

PyInstaller supports a lot of major frameworks and libraries out of the box. This includes —

Babel, Django, IPython, matplotlib, numpy, pillow, PyGTK, PyQt4, PyQt5, scipy, sphinx, SQLAlchemy, wxPython and many more.

If your app depends on any of the above libraries, you don’t need to worry about the hassles of including dependent libraries, dlls, hidden imports, packages or anything else for that matter. PyInstaller takes care of everything for you. It inspects your code recursively and figures out all the dependencies.

Add and bundle resources

Resources can be anything, images, icons, textual data, translation strings. There is a very simple recipe to bundle and access your resources. For simplicity, let’s assume all your resources are available inside a directory called resources as below —

package_dir

├── package

│ ├── submodule_bar

│ ├── submodule_foo

│ ├── __init__.py

│ └── main.py

├── resources

│ ├── bar.dat

│ └── foo.png

├── entry_point.py

└── setup.py

Bundling the resources

Run pyi-makespec entry_point.py -n foobar --onefile . The pyi-makespec script accepts the same arguments as pyinstaller but instead of actually running PyInstaller, it creates a foobar.spec spec file for you to customise, which can then be called with pyinstaller foobar.spec .

Your foobar.spec file should look something like this —

The spec file is simply a python script albeit with some special callables as shown above. To add resources, you simply need to create an array with a list of tuples —

The first string specifies the file or files as they are in this system now.

The second specifies the name of the folder to contain the files at run-time.

A simple script to do the same would be —

You will be adding the above code to the spec file, which should now look like this —

Notice the call to get_resources() in a.datas .

Accessing bundled resources

Quoting from the PyInstaller wiki —

You may need to learn at run-time whether the app is running from source, or is “frozen” (bundled). For example, you might have data files that are normally found based on a module’s __file__ attribute. That will not work when the code is bundled. The PyInstaller bootloader adds the name frozen to the sys module. So the test for “are we bundled?”

To summarise, this is what you need to do to access any resources you have bundled —

Add the following two variables to your utility section —

You can then use this in your entry_point.py as follows —

You can now load your resources in main.py as follows —

Bundle binaries

PyInstaller should automagically bundle any .so or .dll files by inspecting your python module. But in case it fails to do so, it is easy to add them.

Bundling binaries or libraries that your app depends on is pretty much similar to how you would bundle data files.

Assuming the following directory structure —

package_dir

├── bin

│ ├── bar.so

│ ├── bar.dll

│ └── bar.dylib

├── package

│ ├── submodule_bar

│ ├── submodule_foo

│ ├── __init__.py

│ └── main.py

├── resources

│ ├── bar.dat

│ └── foo.png

├── entry_point.py

└── setup.py

Let’s say your app depends on a shared library bar , and you have binaries available for it for all 3 operating systems.

You might go around including them as follows —

You might ask, what’s the difference between adding a file as a data file or a binary file, well quoting from the PyInstaller Wiki —

Binary files refers to DLLs, dynamic libraries, shared object-files, and such, which PyInstaller is going to search for further binary dependencies. Files like images and PDFs should go into the datas

So make sure you are adding any dlls or so files as binaries instead of data files.

Freeze a GUI app

You will probably want to pass the --windowed flag to pyinstaller in order to make sure there is no console while opening the App.

Freeze a macOS app

If you are freezing a one-file windowed macOS app you will want to add an additional callable to your spec file like so —

See the PyInstaller-Wiki for more information about these options.

Note: For simple cases, you can also accomplish all the of the above through flags passed to the pyisntaller or pyi-makespec scripts. See Using Spec Files for more information.

What’s next?

The above recipes should be more than enough for all general use cases. I hope the above provides a basic guide on how to use PyInstaller. For more advanced use cases, you can sift through the PyInstaller Wiki.

If you want to see the above guide in action, you can have a look at the Picard github repo.

In the next part of this blog, we will learn how to make use of AppVeyor and TravisCI along with PyInstaller to bundle our applications.

HALLLLP, I am stuck!

If you find yourself unable to comprehend any part of the guide or have a very particular use-case, leave a comment below, I will be happy to help if I can :)