Pygame.image.load() not working with PyInstaller - python

img_l = pygame.image.load("img.png")
screen.blit(img_l)
With Python Interpreter it works fine, image loads and main.py runs without problems, but when I make it into one file .exe with Pyinstaller, .exe crashes.
I've tried few .spec modifications, but few I've managed to find don't seem to help.
Any ideas sincerely appreciated.
EDIT: got it working with:
img_l = pygame.image.load(os.path.join('img.png'))
screen.blit(img_l, (0, 0))
Now it works as it should after going through PyInstaller :)

For anyone else who is having the same problem and has tried #Esa's answer, you may notice that it sometimes does not work when run outside the directory. This is caused by Pyinstaller still trying to find the relative path and not using the included files instead. This can be fixed by finding the correct path inside your code before loading files:
if getattr(sys, 'frozen', False):
Path = sys._MEIPASS #This is for when the program is frozen
else:
Path = os.path.dirname(__file__) #This is when the program normally runs
This finds the actual path of your file and must be done for every file, e.g:
pygame.image.load(os.path.join(Path, 'Path\\to_file\\from_root'))
sys._MEIPASS is the key as it will find the path when the program is frozen as when a program is frozen, it's files are stored somewhere else.
When you generate the .exe file a .spec file will also be created with the root directory. In there you will need to edit this as follows:
You should see a file structure similar to the one below
Notice how datas is equal to None. You will have to edit this.
This is the .spec file in the root directory currently:
# -*- mode: python -*-
block_cipher = None
#you will have to add things here later
a = Analysis(['file.py'],
pathex=['C:\\path\\to\\root\\folder'],
binaries=None,
datas=None,
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
exclude_binaries=True,
name='game_file',
debug=False,
strip=False,
upx=True,
console=True , icon='icon_file.ico')
Now what we do is we add all our files: Place this added_files below block_cipher but above Analysis(), e.g:
added_files = [
('file1.png', '.') #The '.' represents root folder
('file2.png', '\\folder') #loads file2.png from root\folder
]
Now inside of Analysis() we change the None after datas to added_files. You will also notice that there are the main different options for your final file. You can edit these here if you want but you cannot change the "onefile" option, this is made when the .spec file is created.
Finally to make this new exe file, go to your root folder in cmd and type this:
pyinstaller "PY_FILE_NAME.spec"
The final exe, whether in a folder or not should be in root\dist\Executable_name.exe or root\dist\Executable_name\Executable_name.exe

I ran into this same problem. For some reason the working directory is not set properly for the --onefile packaged executable. I managed to resolve it by using the following piece of code at the beginning of my program.
This is similar to the above proposed solutions but I find it slightly more elegant :)
It basically forces the working directory to the temporary extracted directory in case we are running as a single executable.
import sys
import os
if getattr(sys, 'frozen', False):
os.chdir(sys._MEIPASS)

got it working with:
img_l = pygame.image.load(os.path.join('img.png'))
screen.blit(img_l, (0, 0))
Now it works as it should after going through PyInstaller :)

Sorry, I'm very very new to programming.
I'm getting a similar (the same?) error when I try to run my .exe
It says:
pygame.error: Couldn't open walkr1.png
I tried the fix that you used, but then got the error:
pygame.error: Can't seek in this data source
The image files are in a folder in the folder with the main .py file. I've tried moving the files to the same folder but that didn't work. I've also tried adding the data files to the .spec file, but that doesn't seem to work either...
Was wondering if you could help?
Sorry, I know these are probably all very dumb questions.

Related

Can PyInstaller pack shared object files into executable?

I've written a Python app which uses the tkinter module (among others) on Linux.
Python(3.10) with tkinter support was compiled by myself in a custom location (~/local), as well as the non-python dependencies like tk/tcl, libfreetype2, libpng, etc.
I've then packaged the script with PyInstaller using the --one-file option.
The resulting executable works if I execute it myself.
But copying it to another location and executing it as a different user leads to an
ImportError: /home/*****/local/lib/libtcl8.6.so: cannot open shared object file: Permission denied, because of course that folder is not readable by that user.
I've tried bundling the .so file with both the --add-data and --add-binary option of PyInstaller, but none of it works. Even if I copy the files manually, it's still looking in the custom path.
Is there a way to specify to PyInstaller to package the needed shared object files into the executable or at least change any absolute path into a relative one, so I can bundle the files manually?
You should have a .spec file created first time you have created an executable, Explicitly add all the files which need to be shipped with executable in the spec file data .
https://pyinstaller.org/en/stable/spec-files.html
For example , add datafiles and add it to datas in spec file :
data_files = [(os.path.join(some_path,some_file), '.'), ]
block_cipher = None
a = Analysis(['minimal.py'],
pathex=['/Developer/PItests/minimal'],
binaries=None,
datas=data_files,
hiddenimports=[],
hookspath=None,
runtime_hooks=None,
excludes=None,
cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,... )
coll = COLLECT(...)
Now to generate pyinstaller executable use this spec file .
pyinstaller somename.spec
Do note that in your script dont directly load the files shipped in executable using explict paths instead load in this way , since pyinstaller during runtime in other environments dont pick the embedded files through explict paths but store in its file system so this take care of it :
folder_path = getattr(sys, '_MEIPASS', some_path)
file_path = os.path.join(folder_path,some_file)

How do I resolve a missing utility module preventing my executable from running when I already installed the parent module?

I've written a few Python scripts to create a tkinter GUI for a machine learning algorithm process. I originally coded everything in PyCharm, but I'd really like to put everything together into a stand-alone executable. I've moved my main script and its .py dependencies into their own directory and tested it out using the Command Prompt, and it works great. However, when I run pyinstaller, the executable is created but fails on startup.
The program is made up of three files, with GUI.py being the main script. As mentioned above, I moved the dependent files into a new directory and tested GUI.py in the Command Prompt, and it worked great. Executable is created (albeit with a lot of warnings about missing 'api-ms-win-crt' files) but can't be run.
I created the executable using the command:
pyinstaller --onefile GUI.py
When the executable is run from the command line after creation, I get a big long traceback ending in the following:
File "site-packages\sklearn\metrics\pairwise.py", line 32, in <module>
File "sklearn\metrics\pairwise_fast.pyx", line 1, in init
sklearn.metrics.pairwise_fast
ModuleNotFoundError: No module named 'sklearn.utils._cython_blas'
[3372] Failed to execute script GUI
I know I've already explicitly imported sklearn through the command prompt, but from the traceback, it seems I'm missing a utility module somewhere. I tried to import the missing module specifically, but I got an error that no distributed module was available.
I don't have much experience with pyinstaller, and I have no idea where to go from here. I'm using Windows 10 and Python 3.7.3.
It seems that Pyinstaller can't resolve sklearn import. So one easy way is to just bring the whole module directory which located in <path_to_python>/Lib/site-packages/sklearn/ with executable output. So use below spec file to generate your executable:
# -*- mode: python -*-
block_cipher = None
a = Analysis(['test.py'],
pathex=['<path to root of your project>'],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
a.datas += Tree('<path_to_sklearn_in_python_dir>', prefix='sklearn')
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='test',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=False,
runtime_tmpdir=None,
console=True )
Finally generate your executable with
pyinstaller test.spec
This should resolve import errors for sklearn but if you face other NotFound imports add them like above to spec file.
Building up on M.R.'s answer, you can directly include the path to sklearn in your original pyinstaller command:
pyinstaller --onefile GUI.py --add-data "<path-to-python>\Lib\site-packages\sklearn;sklearn"
which results in the following line of code being added inside a = Analysis() in the automatically-generated GUI.spec file:
datas=[('<path-to-python>\\Lib\\site-packages\\sklearn', 'sklearn')]
Note that the --onefile option will result in an executable that is slower to start up than the default one-folder bundle (based on both the pyinstaller documentation and my own experience bundling up sklearn):
pyinstaller GUI.py --add-data "<path-to-python>\Lib\site-packages\sklearn;sklearn"

After using Pyinstaller to convert .py to .exe the program cant find the correct txt file location

I'm currently trying to convert my python program into an executable but when i do convert it and run the .exe file it throws the error, No such file or directory: 'profiles.txt'.
I'm trying to read and write to the text file based on user input. is there a way i can get my program to find the correct text file so I can get the exe file to work?
If your program depends of other files, you can include it in the program using the Pyinstaller spec files. Spec files contains all the instructions to create your program, including additional data files or missing modules that Pyinstaller cann't find. I strongly recommend you to use it.
A spec file looks like:
block_cipher = None
a = Analysis(['minimal.py'],
pathex=['/Developer/PItests/minimal'],
binaries=None,
datas=[ ('src/README.txt', 'myfiles') ],
hiddenimports=[],
hookspath=None,
runtime_hooks=None,
excludes=None,
cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,... )
coll = COLLECT(...)
The files that you need to provide to your program are in datas=. In this example you will add the file readme.txt in the folder src of your pc to the folder myfiles in the bundled app.

Pyinstaller exe not working when I change the icon

I was making a GUI with python Tkinter. It also uses numpy and matplotlib also. So, I used pyinstaller and make a exe out of the python script. It runs flawlessly and did all what i wanted.
Then I tried to change the tk icon from the gui window (i am using windows 10) with this line
master.iconbitmap(default='image.ico')
other than this line i change nothing of the main program. Then using pyinstaller and I made the exe without any error. But when I tried to run the exe it shows "Fatal Error! file.exe returned -1"
What am i missing? How to fix this problem?
Also I have an additional problem, the 1st exe i build (without changing the icon) is running on Windows-10 and Windows-8 but not in Windows-7. In windows-7 it shows the same error "Fatal Error! file.exe returned -1"
For those still experiencing this issue, I found that pointing the iconbitmap line to the full path will resolve the issue. I was originally having the same problem as the original poster until I entered the full path to my .ico file.
Example:
wm_iconbitmap('E:\icon_name.ico')
try setting datas like:
a.datas += [('C:\\Users\\KoushikNaskar\\Desktop\\Python\\image.ico', 'image.ico')]
from:
http://pythonhosted.org/PyInstaller/spec-files.html#adding-data-files
datas is a list of tuples: (source, dest)
Your problem (most likely) is that you are not bundling the icon's image when using pyinstaller to compile your program to a .exe.
You'll see something like this in your .spec file:
a = Analysis(['your_script.py'],
pathex=['your_path'],
binaries=None,
datas=['file_1_path', ....], # Here
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
Or you could do something like
a.datas += [item1, item2, ...]

How to compile python script to binary executable

I need to convert a Python script to a Windows executable.
I have Python 2.6 installed to python26.
I have created one script and kept it in C:\pythonscript. Inside this folder there are two files
Setup.py and oldlogs.py (this file need coversion)
setup.py code is
from distutils.core import setup
import py2exe
setup(console=['oldlogs.py'])
How can I convert oldlogs.py to an exe file?
Or use PyInstaller as an alternative to py2exe. Here is a good starting point. PyInstaller also lets you create executables for linux and mac...
Here is how one could fairly easily use PyInstaller to solve the issue at hand:
pyinstaller oldlogs.py
From the tool's documentation:
PyInstaller analyzes myscript.py and:
Writes myscript.spec in the same folder as the script.
Creates a folder build in the same folder as the script if it does not exist.
Writes some log files and working files in the build folder.
Creates a folder dist in the same folder as the script if it does not exist.
Writes the myscript executable folder in the dist folder.
In the dist folder you find the bundled app you distribute to your users.
I recommend PyInstaller, a simple python script can be converted to an exe with the following commands:
utils/Makespec.py [--onefile] oldlogs.py
which creates a yourprogram.spec file which is a configuration for building the final exe. Next command builds the exe from the configuration file:
utils/Build.py oldlogs.spec
More can be found here
Since other SO answers link to this question it's worth noting that there is another option now in PyOxidizer.
It's a rust utility which works in some of the same ways as pyinstaller, however has some additional features detailed here, to summarize the key ones:
Single binary of all packages by default with the ability to do a zero-copy load of modules into memory, vs pyinstaller extracting them to a temporary directory when using onefile mode
Ability to produce a static linked binary
(One other advantage of pyoxidizer is that it does not seem to suffer from the GLIBC_X.XX not found problem that can crop up with pyinstaller if you've created your binary on a system that has a glibc version newer than the target system).
Overall pyinstaller is much simpler to use than PyOxidizer, which often requires some complexity in the configuration file, and it's less Pythony since it's written in Rust and uses a configuration file format not very familiar in the Python world, but PyOxidizer does some more advanced stuff, especially if you are looking to produce single binaries (which is not pyinstaller's default).
# -*- mode: python -*-
block_cipher = None
a = Analysis(['SCRIPT.py'],
pathex=[
'folder path',
'C:\\Windows\\WinSxS\\x86_microsoft-windows-m..namespace-downlevel_31bf3856ad364e35_10.0.17134.1_none_50c6cb8431e7428f',
'C:\\Windows\\WinSxS\\x86_microsoft-windows-m..namespace-downlevel_31bf3856ad364e35_10.0.17134.1_none_c4f50889467f081d'
],
binaries=[(''C:\\Users\\chromedriver.exe'')],
datas=[],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
name='NAME OF YOUR EXE',
debug=False,
strip=False,
upx=True,
runtime_tmpdir=None,
console=True )

Categories

Resources