Convert Your Python Script to Executable File
Have You ever wanted to share some sort of Your script with others, but did not want to give the source code? Or maybe You want to share an amazing program that You wrote with people, who have not ever seen any code and don’t know what programming is? It turns out that there is an easy way to create executable files in Python using pyinstaller package. Official documentation can be found below:
Nevertheless in this article I will try to cover as much practical examples as possible so that documentation is left for some other more specific tasks.
Example Application
Personally for me, it is always fun to see that application is doing something in your environment, that’s why for this tutorial we are going to build an executable file, which will create a new empty folder every time it is run. To make it a little bit more fun, folder name will be equal to the date and time at which the executable file was run. By the way, working with Time and Date in Python is quite easy. I have already written about it in my other article which You can find here:
So just to explore a few other possibilities of different pyinstaller build options, I will add a few print statements and a delay at the end of the code. So let’s start by importing all modules that we are going to need in this example:
from datetime import datetime
import os
import time
In this example, datetime class from datetime module will be used to retrieve current time, because we want our folder name to be equal to current time. Another module, which is called os, will be used to retrieve working directory in which the script is running and to create a new folder under that particular directory. Finally, time module will be used to create delay at the end of the application.
Now we can read current time using datetime class:
datetime_obj = datetime.now()
print(f"datetime_obj = {datetime_obj}")
print(f"datetime_obj type = {type(datetime_obj)}")
Output:
datetime_obj = 2021-09-19 11:57:08.004920
datetime_obj type = <class 'datetime.datetime'>
Keep in mind, that your datetime_obj value will be different, because it literally changes every microsecond and it depends on the time when you are running the script. I have also added a print to show the type of our datetime_obj.
Next thing to do is to convert this datetime_obj to string, so we could use it to form a directory name for creating a new folder. One more thing to note is that datetime_obj contains a colon symbol ‘:’ which is not allowed to use for file naming in Windows, so we will change ‘:’ to ‘_’ symbol using replace method.
folder_name = datetime_obj.strftime("%Y-%m-%d %H:%M:%S.%f")
folder_name = folder_name.replace(':', '_')
print(f"Folder name will be: {folder_name}")
print(f"folder_name type = {type(folder_name)}")
Output:
Folder name will be: 2021-09-19 11_57_08.004920
folder_name type = <class 'str'>
As you can see, our folder_name is now str class object, not datetime, so we can use it now to form directory name which we will create.
Now, it is time to use os module to get current working directory. This will help us to form final directory for our new folder.
cwd = os.getcwd()
print(f"Current working directory: {cwd}")
folder_directory = cwd + "\\" + folder_name
print(f"Will try to create new folder: {folder_directory}")
Output:
Current working directory: C:\python_projects\pyinstaller_example
Will try to create new folder: C:\python_projects\pyinstaller_example\2021-09-19 11_57_08.004920
Note that when forming folder_directory I add three strings together, and one in the middle is “\\”. We need this because in Python backslash symbol ‘\’ is used as an escape character.
At this stage, we are ready to create our new folder using formed folder_directory.
try:
if not os.path.exists(folder_directory):
os.mkdir(folder_directory)
print(f"Successfully created directory: {folder_directory}")
except Exception as e:
print(f"Failed to create directory! {e}")
Output:
Successfully created directory: C:\python_projects\pyinstaller_example\2021-09-19 11_57_08.004920
A few things to note here. First, in this case I received this output because new directory was created successfully. I could have received an Exception with print, showing that new directory creation failed. Second, I have added a code to catch absolutely any Exceptions that might occur while creating a new directory and that is not a good practice in general, but I will leave it like this here so that it would catch any unexpected errors that You might encounter. Third, os.path.exists() is used to check if directory You are about to create already exists, and if it’s not, then we create that new directory using os.mkdir() method.
At this point, example application which I wanted to show You is almost done. Last part of the code I wanted to add is shown below:
print("Finish!")
time.sleep(5)
What happens here is I am using time.sleep() to make add delay for 5 seconds before exiting once it is finished (I will explain a little bit later why I have done this when).
Below is full code snippet which is used in this example application:
That’s it. We have finished our example application which we will be packing into executable file. You can run the script alone if you want and it will work and you could see the results, but my goal here is to show how to create executable file, so I will demonstrate results in the end with executable file.
Pyinstaller for creating Executable file
At this point, I would suggest you to clone this example application code from my github repository https://github.com/vycart/pyinstaller_example, or if You followed along and written the code Yourself, then look at the next step.
Once you have cloned the repository and finished setting up and activating virtual environment, we can actually now install pyinstaller.
pip install pyinstaller
To check if pyinstaller is installed successfully, you can run
pyinstaller --version
Output:
4.5.1
At the time of writing, this is newest pyinstaller version. If you got everything correct up until this point, now it is time to actually build the executable. We do this by executing the following:
pyinstaller main.py
If everything ran successfully, you should see a few new directories created under your working directory. Below is an example of what you should be seeing:
Now, to find your executable, you have to go under dist directory and enter main folder. You should be seeing something like in the image below
Now, if you run this file, you will see a new popup window which will show all the print statements that we had added in the code.
Now this window closes automatically after 5 seconds. That is we reason why I have added time.sleep(5) at the end of the code, so You are be able to see the output of the executable file.
Now if You run this executable for a few more times, you will see new directories created in the same folder where your executable is. Example is provided below
Now the big disadvantage of this way for creating executable files is actually that you have to copy all contents that are inside main folder (everything that is inside the folder where executable file is located) and it would be much better if we don’t have to do this. And there actually is a way for doing this, but before doing the next step I recommend to delete dist folder from working directory so you would not get confused after a new executable is created in the next step. In other words, your folder view should look like this before doing next step:
I want to actually note that it is not necessary to do this step, but I think it will be less confusing now this way. Later you can experiment on your own and see the difference.
Put everything into single executable
Pyinstaller has quite a lot of options for building an executable and it is not possible to go through all of them in single article and explain everything in detail, but I want to show you a few most important things which you might want to do, and one thing is obviously having single executable file which You can share with anyone and it would work on other machines. For that You have to use--onefile
option:
pyinstaller main.py --onefile
After running this, You will see the same view as in Figure 1, but dist folder content will be different this time and you will see only single executable file:
Now this is way better. You can share this executable file with anyone You want, and it is the only file that You need to share, because all dependencies that are needed for this executable to run are packed inside. You can actually see from the Figure 1, that during first method main executable file was about 1.4 KB in size, but now it is about 4.8 KB in size, but it is still much smaller than whole dist directory with all .dll files which we had using the first method.
Now You can copy this executable to any folder You want and run it from there, and You will see the same thing as previously (popup window as in Figure 3, and new directory once the program is finished).
Changing executable name
One more thing that I want to show is how to change executable name. You probably don’t want all your executables to be called main. You can do that by using--name
option. So if You want to create a single executable with name MyExecutable, You can do it using the following:
pyinstaller main.py --onefile --name MyExecutable
Now Your output executable file will have Your described name:
I want to note that You might encounter some issues if You want to add underscores to executable file name. It is possible to overcome them, but I would recommend picking names without underscores at this point.
Hiding popup window
Last thing I want to talk about is how to hide popup window which shows up when you launch your executable file (Figure 3). Now it is possible that you want to debug Your application and it is ok for You to see what is happening, but people You are sharing Your application with might don’t need that. Plus, if You are creating graphical user interface (GUI), You definitely want to hide that window, so it would not disturb users. For that, you need to specify another option to pyinstaller which is--windowed
pyinstaller main.py --onefile --name MyExecutable --windowed
After running this, Your output executable will look exactly the same as in Figure 7, but after launching it popup window which is shown in Figure 3 will not be visible anymore. So at this point You could also remove 5 seconds delay from the end of the script and rebuild executable.
Conclusion
It is quite easy to build simple executable files using pyinstaller package. Of course, there are a lot more complex things which we could do with it, but it would make much more sense to write about this in another article.
Anyways, I hope that now You should be able to turn Your python scripts into executables, which You could share with Your friends or colleagues.
If You have any questions, feel free to ask and I will be happy to answer them.
Thank You for Reading.