I am trying to compile a python file with Nuitka in stead of Pyinstaller. Everything is going great except for the facts that I do not understand how I should add another data file to the python file.
The problem
If I want to add an image to my python file in Pyinstaller (in Windows) I would do:
wine /root/.wine/drive_c/Python27/pyinstaller.exe --add-data "/root/Downloads/car.jpg;." --onefile --noconsole --icon /root/Downloads/icon.ico pythonfile.py
Now if I would open this exe file I would run the python file and open the car.jpg file.
I want to do something similar using Nuitka. When I looked at the documentation of Nuitka I saw that I probably needed to use the --include-data-file=<source>=<target> argument.
I tried this and it gave no errors, but when I open the created exe file, it does not open the given file. All the other arguments worked as I wanted, so only the --include-data-file argument does not give the wanted result
This is the Nuitka command I tried:
.\python.exe -m nuitka --mingw64 .\pythonprogram.py --standalone --onefile --windows-icon-from-ico=pdf.ico --windows-disable-console --include-data-file=C:\Users\User\AppData\Local\Programs\Python\Python39\*.pdf=mypdf.pdf
My question(s):
Am I using the correct argument?
Is this even possible with Nuitka?
How would I fix my problem?
Thanks in advance!
First of all, when encountering unexpected behaviour in Nuitka (in this case, you'd expect a file to open, which it didn't) I highly recommend removing the --windows-disable-console argument and observing the terminal output; without it debugging the compiled program is virtually impossible. You can also get a lot of information by analyzing Nuitka's output during transpiling and compilation (for example, there may appear a warning informing you about including numpy's plugin in order to add support for the numpy module).
Now, moving on to your questions:
Am I using the correct argument?
Yes, argument --include-data-file=<source>=<target> is correct if what you want is to embed one file.
What is however very important when it comes to programs compiled with --onefile argument is how the files are loaded internally, in the .py files.
I feel like the best thing I can do is show an example of my own (I'm using pygame for my project, but this way of loading files should work in any circumstance):
import os
import pygame
def load_file(file_name: str) -> str:
return os.path.join(os.path.dirname(__file__), file_name)
image_1_sprite = pygame.image.load(load_file("textures/image_1.png"))
I would then use Nuitka as such: python -m nuitka --onefile --include-data-dir=../workingdir/textures=textures main.py or, if you want to include just one file, python -m nuitka --onefile --include-data-file=../workingdir/textures/image_1.png=textures/image_1.png main.py, where workingdir is the directory in which main.py resides (I recommend using relative paths to make the repository portable, because if someone were to download your source code and save it, for example, on the D:\ hard drive - the executed command would fail).
Related
So I have made this python file which I want to compile (it's called ElPatron) to a .exe file with Nuitka.
I did it correctly and this is the dist folder that came with that (using the --standalone argument that Nuitka has)
This is the nuitka command I used:
.\python.exe -m nuitka --mingw64 .\ElPatron.py --standalone --onefile --windows-disable-console --windows-icon-from-ico=pdf.ico --include-data-file=C:\Users\User\AppData\Local\Programs\Python\Python39\example.pdf=example.pdf
I included the pdf in the exe using the --include-data-file argument from Nuitka
The problem I have now is that I don't know where this(the example.pdf) get's stored when the ElPatron.exe is executed. I want to know this so I can call it inside my Python project.
The question
Where does the example.pdf get stored when a windows computer executes the .exe (containing the pdf)?
From looking at the Nuitka documentation, it says:
# Create a binary that unpacks into a temporary folder
python -m nuitka --onefile program.py
Note
There are more platform specific options, e.g. related to icons,
splash screen, and version information, consider the --help output
for the details of these and check the section “Good Looks”.
Again, on Windows, for the temporary file directory, by default the
user one is used, however this is overridable with a path
specification given in
--windows-onefile-tempdir-spec=%TEMP%\\onefile_%PID%_%TIME% which is
the default and asserts that the temporary directories created cannot
collide.
So, I think the output should show up as a subdirectory in %TEMP% as described, which should be the path C:\Users\%USERNAME%\AppData\Local\Temp\.
If you want to use the default path, you'll have to find the dynamically-named subfolder (onefile_%PID%_%TIME%) within %TEMP% in Python, and you can get the current process ID, then use a fuzzy pattern or something, as you won't be able to know the exact time. Otherwise, set a custom path.
A janky way of doing this might be:
def resource_path(self,relative_path):
""" Get absolute path to resource, works for python file and compiled exe """
if not sys.argv[0].endswith('exe'): return os.path.join(os.path.dirname(sys.argv[0]),relative_path)
else:
if not hasattr(self,'respth'):
temp_appd=os.path.join(os.getenv('localappdata'),'Temp')
resdict={}
for item in os.listdir(temp_appd):
if len(re.findall('''onefile_\d+_\d+''',item))>0:
resdict[re.findall('''onefile_\d+_(\d+)''',item)[0]]=item
self.respth=resdict[max(list(resdict.keys()))]
logging.info('path set to '+os.path.join(os.getenv('localappdata'),'Temp',self.respth,relative_path))
return os.path.join(os.getenv('localappdata'),'Temp',self.respth,relative_path)
I have a question if I use Pyinstaller to convert python file to exe will convert the modules with or not? , because i have python file with a lot of modules and i want to convert it how i can do it and avoiding this issue,
Thank u.
import requests
error:
ImportError: No module named requests
.
After discussion in comments basically the error is occurring when you try to open the generated file in another computer, however your aren't using any virtual environment so you can install the requirements and try to rebuild again but rather you want a stanalone exe file.
For that use :
pyinstaller --onefile your-script.py
# or pyinstaller -F your-script.py
## this should generate a stand alone executable file located in the dist folder.
About your concerns on how pyinstaller works
Does pyinstaller make copies of modules when building ?
The answer is simply : yes , as mentioned in the docs here PyInstaller reads a Python script written by you. It analyzes your code to discover every other module and library your script needs in order to execute. Then it collects copies of all those files – including the active Python interpreter! – and puts them with your script in a single folder, or optionally in a single executable file.
However, the variations of Python and third-party libraries are endless and unpredictable, if something goes wrong you can learn how to fix those issues by reading this page on the docs here
What to generate ?
you can read more here
Create a one-folder bundle containing an executable (default), -D, --onedir
Create a one-file bundled executable. you need to use -F ore --onefile
Finally
I highly encourage you to use separate virtual environment for each project.
I am having a tough time overcoming this error, I have searched everywhere for that error message and nothing seems relevant to my situation:
"failed to execute script new-app"
new-app is my python GUI program. When I run pyinstaller using this command:
pyinstaller.exe --onedir --hidden-import FileDialog --windowed --noupx new-app.py
It does work smoothly. In addition, when I execute the command line to run the gui program, it works perfectly and the GUI is generated using this command:
.\dist\new-app\new-app.exe
But when I go to that file hopefully to be able to click the app to get the GUI, it gives me the error said above. Why is that?
I am using python2.7 and the OS is Windows 7 Enterprise.
Any inputs will be appreciated and thanks a lot in advance.
Well I guess I have found the solution for my own question, here is how I did it:
Eventhough I was being able to successfully run the program using normal python command as well as successfully run pyinstaller and be able to execute the app "new_app.exe" using the command line mentioned in the question which in both cases display the GUI with no problem at all. However, only when I click the application it won't allow to display the GUI and no error is generated.
So, What I did is I added an extra parameter --debug in the pyinstaller command and removing the --windowed parameter so that I can see what is actually happening when the app is clicked and I found out there was an error which made a lot of sense when I trace it, it basically complained that "some_image.jpg" no such file or directory.
The reason why it complains and didn't complain when I ran the script from the first place or even using the command line "./" is because the file image existed in the same path as the script located but when pyinstaller created "dist" directory which has the app product it makes a perfect sense that the image file is not there and so I basically moved it to that dist directory where the clickable app is there!
So The Simple answer is to place all the media files or folders which were used by code in the directory where exe file is there.
Second method is to add "--add-data <path to file/folder>"(this can be used multiple times to add different files) option in pyinstaller command this will automatically put the given file or folder into the exe folder.
In my case i have a main.py that have dependencies with other files. After I build that app with py installer using this command:
pyinstaller --onefile --windowed main.py
I got the main.exe inside dist folder. I double clicked on this file, and I raised the error mentioned above.
To fix this, I just copy the main.exe from dist directory to previous directory, which is the root directory of my main.py and the dependency files, and I got no error after run the main.exe.
Add this function at the beginning of your script :
import sys, os
def resource_path(relative_path):
if hasattr(sys, '_MEIPASS'):
return os.path.join(sys._MEIPASS, relative_path)
return os.path.join(os.path.abspath("."), relative_path)
Refer to your data files by calling the function resource_path(), like this:
resource_path('myimage.gif')
Then use this command:
pyinstaller --onefile --windowed --add-data todo.ico;. script.py
For more information visit this documentation page.
In case anyone doesn't get results from the other answers, I fixed a similar problem by:
adding --hidden-import flags as needed for any missing modules
cleaning up the associated folders and spec files:
rmdir /s /q dist
rmdir /s /q build
del /s /q my_service.spec
Running the commands for installation as Administrator
I was getting this error for a different reason than those listed here, and could not find the solution easily, so I figured I would post here.
Hopefully this is helpful to someone.
My issue was with referencing files in the program. It was not able to find the file listed, because when I was coding it I had the file I wanted to reference in the top level directory and just called
"my_file.png"
when I was calling the files.
pyinstaller did not like this, because even when I was running it from the same folder, it was expecting a full path:
"C:\Files\my_file.png"
Once I changed all of my paths, to the full version of their path, it fixed this issue.
I got the same error and figured out that i wrote my script using Anaconda but pyinstaller tries to pack script on pure python. So, modules not exist in pythons library folder cause this problem.
That error is due to missing of modules in pyinstaller. You can find the missing modules by running script in executable command line, i.e., by removing '-w' from the command. Once you created the command line executable file then in command line it will show the missing modules. By finding those missing modules you can add this to your command :
" --hidden-import = missingmodule "
I solved my problem through this.
I had a similar problem, this was due to the fact that I am using anaconda and not installing the dependencies in pip but in anaconda. What helped me was to install the dependencies in pip.
I found a similar issue but none of the answers up above helped. I found a solution to my problem activating the base environment. Trying once more what I was doing without base I got my GUI.exe executed.
As stated by #Shyrtle, given that once solved my initial problem I wanted to add a background image, I had to pass the entire path of the image even if the file.py and the image itself were in the same directory.
In my case (level noob) I forgot to install library "matplotlib". Program worked in Pycharm, but not when I tried open from terminal. After installed library in Main directory all was ok.
I've written a program that generates a random name and displays a random image along with it using Python and tkinter. However, I want the user to be able to add and remove pictures as well as edit the names of students. That being said, I don't want to package these inside the executable where it can't be changed by the user.
To use PyInstaller, I go into the command prompt and navigate to the working directory and type:
pyi-makespec --windowed --onefile --icon=Assets\\icon.ico random_student.py
Then, in the spec file I change datas to:
datas=[('Assets\\icon.ico', 'Assets')],
Then, I run
pyinstaller random_student.spec
The program runs just fine using PyCharm. And I've done this exact same method on a couple of other .py files an it works. However, they don't need to pull images/text into their programs. This will create an executable, but I can't run it. It gives me a Fatal Error "Failed to execute script random_student". I've tried placing the executable in the working directory and in the pictures folder, but neither work.
I'm currently using Windows 10 64-bit and Python 3.6.6
I'd appreciate any kind of help I can get with this!
SOLUTION: I removed the --windowed option so I could actually read the error. Then realized I didn't have Pillow installed so it was unable to be packaged. Thank you for the help.
So I'm using pyinstaller with python27, and my exe works great so long as it's in the same directory as the build folder. I need it to be a completely standalone exe, without any dependencies, is there a way to bundle the important things from the build folder into one file? Neither -F nor --onefile seems to do this.
Edit: as I explain in my answer below, I thought pyinstaller was the problem because the exe would only run in the dist folder, so I assumed it had dependencies there, but in reality, it was running and then instantly crashing due to a bug that only triggered when the exe was on the desktop.
I figured out that the reason it wasn't working had nothing to do with pyinstaller or dlls. The exe was opening, and and trying to input powershell commands via python like it was supposed to. Unfortunately I had a line of code that said this:
subprocess.check_output('schtasks /create /sc minute /mo ' + str(time) + ' /tn "test_process_to_run_every_'+str(time)+'_min" /tr //'+sys.argv[0],shell=True)
#set this exe to run every X minutes in windows scheduled tasks
the problem was that sys.argv[0] changed when I put the exe on the desktop, and ended up being a path that looked like C://Users/John Smith/Desktop. The space in between John and Smith made powershell mad and crashed the program, so I escaped it using this line of code:
path = sys.argv[0].replace(" ","^")
and then I replaced sys.argv[0] with my new path variable. Hope this helps anyone in the future trying to do the same thing.
after pyinstaller has converted your script into .exe, than you need to add the executable to path, otherwise you have to open the command line in the directory that the file is in. pyinstaller just puts your script and py interpretor into a single file. same goes for linux.
for dependency side, look here.
there are other options you can try to bbFreeze, py2exe, cx_Freeze
to use pyinstaller in a simple way:
pyinstaller --onefile your_file.py
now you should see couple of files build, dist(exe in here).
NOTE: that --onefile flag doesn't necessarily get rid of the need for it to have link with certain libraries, it will still need those in order to run.
prepare for distribution, first need to get a spec file:
to get a spec file:
pyinstaller --noconsole your_file.py
than you can get the exe file for distribution like so:
pyinstaller your_file.spec
for more info and tutorial look here
see if nuitka works for you, it might sound scary but it is not. it compiles your code to executable binary format. Be aware that under the hood first it converts to c++ API calls.
if you dont like that for closed source program use Cython, and for no dependency use py2exe