Python and pandas are a great team for data science. But what if you need to deliver a script to a Windows client who does not have Python installed?

This is a quick tutorial for converting Python scripts (.py) to standalone, one-file Windows executables (.exe).

1
pyinstaller -F my_script.py

Get a 20Mb exe file that is fully functional on every Windows machine!

tl;dr: If you need one standalone file that works on machines without a Python distrubution go for Pyinstaller. Just be aware of some overhead when importing certain libraries.

Python to exe

My aim was to build an .exe-file of a Python script involving pandas with the following specs:

  • standalone
  • one file, i.e. one .exe-file with everything included
  • no installer for client setup
  • should work “plug-‘n’-play”
  • as small as possible

In the end I managed to get exactly what I wanted but it was a long and troublesome way to go.

There are plenty of python-to-exe scripts/programs/compilers out there but after testing the most used ones only Pyinstaller satisfied my needs. None of the other fulfilled all the above-listed criteria!

Pyinstaller & Pandas

I tried Pyinstaller some years ago and remembered, that somehow I got it working. The big issue with Pyinstaller are that some Python packages do not work out-of-the-box and require some overhead, particular installations, dependencies or settings which can be quite troublesome to figure out.

Out there are tons of outdated docs, stackoverflow questions, guidelines and medium articles that simply didn't help. Only a few pointed to the right direction.

Some banana skins

Let's get to the point. Some Donts first:

  1. Don't use conda for virtual env
  2. Don't use conda for installing libraries

Workflow

1. Set up a virtual environment

You simply cannot skip this step as otherwise all your global Python libraries you ever installed will end up in the .exe which can lead to a couple of GB.

Also, do not use conda! I tried with conda envs but simply failed. The trick here is to go for virtualenv and only use pip to install packages.

1
2
3
4
mkdir project_folder
pip install virtualenv
virtualenv venv 
"venv/scripts/activate" 

The cool thing with venv is, that you could just provide the venv folder to anyone and Python will all it's dependencies simply works. The folder has around 170Mb in my case.

2. Install your packages

Just install all you need but do not use conda! Particularly not to install pandas! Just stick to pip.

1
2
pip install pandas
pip install openpyxl 

Note that openpyxl is needed for some pandas functions to work.

3. Create the spec-file

Pyinstaller uses a spec-file to define the settings. You need to create it first and change the values.

1
pyi-makespec --onefile my_script.py

This will create a my_script.spec file.

Note that the command pyi-makespec is installed with pyinstaller.

4. Download upx for compression

Download the latest upx version to get file compression. In my case it helped to save 15%-20% file size. Save upx.exe to your working directory.

5. Get the settings right

Open the spec-file and use this boilerplate settings. Just alter the directory and the name and the name of the script.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# -*- mode: python ; coding: utf-8 -*-


block_cipher = None

a = Analysis(['my_script.py'],
             pathex=['C:\\Users\\your_directory'],
             binaries=[],
             datas=[],
             hiddenimports=['pandas'],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          name='my_script',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True,
          icon='favicon.ico') # if you need it, provide it in the dir

6. Compile!

The last part is the easiest. Just tell pyinstaller to create the standalone exe.

1
pyinstaller -F my_script.spec

Done! This shouldn't take longer than 15 secs and outputs a <20Mb exe file in the dist folder. It works on every Windows machine without Python installation!