edit: How To Use --add-data with an entire folder?
Im converting my .py file to .exe using pyinstaller. but when i run it, it gives me this error:
Failed To Execute Script "test.py" due to unhandled exception: Couldn't open "C:\Users\Dani\AppData\Local\Temp_MEI11962\button_start.png" no such file or directory
Failed To Obtain/Convert Traceback!
Therefore My Converted Python File (exe) Was in the same directory As My Image.
My path code is built like this:
from locate import this_dir
path = this_dir()
str(path) + "\\button_start.png"
A possible solution is to use pyinstaller's --add-data argument as shown in the documentation. You can either append this to your command when building the .exe or include that in a pyinstaller.spec file.
Additional information:
When you execute a .exe, that was created with pyinstaller, it will create a temporary folder that is named _MEI<some numbers>, just as you showed above. In there, it expects all the necessary files. Therefor, this is also the place, where it will search for the image, no matter where you put your .exe to or where you execute it. Since this folder is generated temporarily every time you start the .exe, it would not help to simply copy your image there.
Related
If this is happening to you, the error (In this case) is a broken installation of pyinstaller or python, remove it from the computer and do a fresh reinstallation.
When trying to create a exe with pyinstaller, it works fine and the bundled .dll file is included an it unpacks the _MEI folder with the necesarry files the correct places. BUT i creates one called _MEIxxx but tries to open a _MEIxxY which does not exist (yes, both changes name everytime it is launched)
I cannot see anywhere you can manually set the name of the _MEI folder which would make it much easier.
The cmd command i am running is:
pyinstaller script.py --add-data "PATH TO DLL\python39.dll;test" -F --runtime-tmpdir .
reproducible problem:
creating a fresh .py project with python 3.9(i use pycharm)
include code of:
print("HI")
then in cmd use:
pyinstaller main.py -F (we want it to be a onefile exe)
Then the .exe file is copied to another pc
Here we run it with CMD to see the error output.
It returns the error:
Error loading Python DLL: "path to local\Temp\_MEIXXXX\python39.dll
the error (In this case) is a broken installation of pyinstaller or python, remove it from the computer and do a fresh reinstallation.
I developed my code using PyCharm and am using PyInstaller to create a desktop .exe application. I am able to create the application, however, my current method requires navigating multiple directories, and to copy/paste some file dependencies. The whole reason to use PyInstaller was to make it more user-friendly, and easy to access the file dependencies. My question is, how should my code be organized so that a general user can easily access the file dependencies, and developer not need to copy/paste the dependency?
Below is my generalized current approach and the result.
To develop using PyCharm, edit:
/projectFolder/main.py,
/projectFolder/helper.py,
/projectFolder/data.xlsx
To create application using PyInstaller:
in command prompt, /projectFolder/venv/Scripts, execute pyinstaller ../../main.py
This creates projectFolder/venv/Scripts/dist/main/main.exe, among many more files (generated by PyInstaller) that the user shouldn't interact with or even see.
At this point, I need to copy/paste /projectFolder/data.xlsx into /projectFolder/venv/Scripts/dist/main for the .exe application to function.
The executable is now ready to be used.
I am looking for a better approach, where the user will see only the relevant files, main.exe and data.xlsx (since this will be modified, periodically). Also, I'd like data.xlsx need not be copy/pasted.
Again, how should I organize my code / package the distribution in order to simplify things for the user?
You can add files or even a folder to install with PyInstaller by using the command --add-data. The documentation explains the format for the file / folder to add but in your case it should be:
pyinstaller --add-data "data.xlsx;." main.py
Now your 'data.xlsx' will automatically copied and pasted into the folder with your .exe file.
PyInstaller also has a feature to compress all your files into one single .exe (including added data) and then when you run your program, it creates a temporary folder in your OS temp folder, usually C:\Users\USERNAME\AppData\Local\Temp\ that starts with _MEIxxxxx where the xxxx is a randomly generated number so your exe programs wont interfer with each other if more than one is running at a time. The folder is automatically deleted upon successful exit of the program.
The code to have only one file instead of a folder:
pyinstaller --onefile --add-data "data.xlsx;." main.py
There are 2 issues with having one file instead of a folder. The first isn't too big of a problem, but everytime your program crashes or doesn't close properly, the temp folder _MEIxxxxx where all your program was unloaded to wont get deleted, potentially clogging up their system. A simple fix would be to add some extra code into your program that checks if there is already a _MEIxxxxx folder with an older date/time in their temp folder and delete it.
The second is that if your program requires to read / write to a file, the code will check in the current directory of the exe, not the temp folder that is created. A workaround to this would be to write some extra code that looks for the a folder that starts with _MEI in their temp and uses that as the path. If it finds more than one folder with _MEI it should take the most recent (and hopefully delete the older ones)
Another cool feature is adding the --runtime-tmpdir command to your pyinstaller which allows you to specify the where you want your _MEIxxxxx to unload, potentially making it easier to check where the data and files you need to run the program.
pyinstaller --onefile --runtime-tmpdir "C:\TemporaryFolder" --add-data "data.xlsx;." main.py
Unfortunately, if you specify a folder or a path that doesn't exit your program wont work at all, so I would recommend creating a separate setup.exe that creates that folder for them and that should be run before running the main.exe file. Afterwards they can delete the setup file and their program should be running.
I created an application that reads a text file to get a digit (1 or 0) to execute some code (it runs like a save file since I want the value to be changed permanently, not just while the script is running), but when I use pyinstaller to convert it to a standalone exe file I get a Fatal Error saying that it cannot run the script. Previous compilations from before I added this feature worked, so I know it's something to do with reading that text file.
Note: I tried using a .py file instead of a .txt. While it worked as a script, the same error came up after compilation.
this is what I type into an elevated command prompt:
pyinstaller --onefile --add-data save.txt;.' file.py
You can not edit the data files that you have bundled with your application using --add-data in pyinstaller's --onefile method as it unpacks all the files into a temporary directory when executed, therefore the file wiil not be found in the current directory as the application demands, so you end up with the Fatal Error.
To get around this, refer to this post, use that function in your code and send your relative path into it, so as to get the absolute path of the file when the application is run. Remember, the changes that you make will be lost after you close the application, as these files are treated as "data files", they are not intended to be modified, so the binary will create a new copy of initial file on every application launch.
If you want it to permanently be stored somewhere, you can implement the file creation (if it doesn't exist) form the script itself, by creating a directory in the AppData folder and save the file there.
Currently to use Pyinstaller I open a Python command console then go to the location of my .spec file using cd and type pyinstaller Software.spec. It works well but I'd like to automate that and have a .bat file do those operations for me.
I have made small .bat files to execute my programs (see below) and I thought the structure for calling Pyinstaller would be close but I'm groping.
C:\Python\python-3.6.3.amd64\python Software.py
pause
Failed attempts of .bat files to run Pyinstaller include:
C:\Python\python-3.6.3.amd64\python\Scripts\pyinstaller.exe Software.spec
C:\Python\python-3.6.3.amd64\python CALL :pyinstaller Software.spec
Any idea would be welcome.
Solution
We need to execute Pyinstaller.exe with Python like so:
"path\to\python.exe" "path\to\pyinstaller.exe" "path\to\my\Software.spec"
Typically you need to call the path to the script as well, but also always double quote paths to ensure you do not get some whitespace kreeping in. Always call the full extension name of an executable as good measure.
"C:\Python\python-3.6.3.amd64\python.exe" "C:\path\to\Software.py"
You can also start it, but in the same batch window:
start /b "" "C:\Python\python-3.6.3.amd64\python.exe" "C:\path\to\Software.py"
or with pyinstaller.exe example:
"C:\Python\python-3.6.3.amd64\python\Scripts\pyinstaller.exe" "C:\path\to\Software.spec"
A simple drag and drop of any python file will result in a compiled exe file in the dist folder created from executing the pyinstaller script.
#echo off
PATH = "%PATH% + %USERPROFILE%\AppData\local\programs\python\Python38"
:: %1 is the file dropped on the batch file
pyInstaller --windowed --onefile %1
If you change %1 to the filename it will also work. Save the script as Pyinst.bat then drag and drop a python file onto it.
I have created a python script and converted it into a .exe file by using:
Pyinstaller –-onefile RFOutputGraphs.py
It works, however one of the jobs in the scripts is failing, despite it working perfectly when run from Python.
My error is:
FileNotFoundError: [Errno 2] no such file or directory:
'C:\\Users\\Nicholas\\AppData\\Local\\Temp\\_MEI30362\\currency_converter
\\eurofxref-hist.zip'
I am guessing it is not recognising what is probably an unusual module (currencyconverter)
Is there a way of fixing this?
Thank you
You can include the zip file in the .exe created by Pyinstaller using the --add-binary option as:
Pyinstaller --add-binary <path to zip>;currency_converter --onefile RFOutputGraphs.py
This copies the zip file from its location on your PC into the .exe file, and arranges for it to be extracted into the currency_converter folder (the location mentioned in the error message) when the .exe is run. Have a look at Using Pyinstaller.