Overcoming PyInstaller Pitfalls – Part 1

Pitfall 1: PyInstaller overwrites spec file

The first time you run pyinstaller you run it with

pyi-makespec my_module.py

instead of

pyinstaller my_module.py

pyi-makespec will generate a my_module.spec which you can alter. Afterwards you just ran

pyinstaller my_module.spec

to avoid overwriting the spec file.

Pitfall 2: Packing additional resources

If You want to have additional files in your distribution you can alter the .spec file:

a = Analysis(['my_module.py'],
             datas=[("docs/user_manual.txt", ".")],

Pitfall 3: Templates not found after packaging

If you are using for example a templating engine like jinja2 and have to access the templates from the distribution you have to fiddle with the path:

path = os.getcwd()
if getattr(sys, 'frozen', False):
    logger.debug("We are running in a bundle!")
    path = getattr(sys, '_MEIPASS', os.getcwd())
    logger.debug("Bundle path" + path)

file_loader = FileSystemLoader(os.path.join(path, 'templates'))
env = Environment(loader=file_loader)
template = env.get_template('template.html')

Pitfall 4: Running PyInstaller from an virtual environment

When running PyInstaller from inside a virtual environment you sometimes get

 File "C:\Python37\lib\ntpath.py", line 183, in split
p = os.fspath(p)
TypeError: expected str, bytes or os.PathLike object, not NoneType

In that case you can pactch venv/Lib/site-packages/PyInstaller/depend/bindepend.py with the following snippet:

# Work around for python venv having VERSION.dll rather than pythonXY.dll
if is_win and 'VERSION.dll' in dlls:
    pydll = 'python%d%d.dll' % sys.version_info[:2]
    if pydll in PYDYLIB_NAMES:
        filename = getfullnameof(pydll)
        return filename

Source: github link

Pitfall 5: Making a single file executable

When You want to get a single file executable you can use the -F flag (or –onefile) for generating the .spec-file. This works only when you have no additional data which should be copied 🙂

pyi-makespec -F my_module.py