Using a site-packages path for pyinstaller - python

I'm creating a pyinstaller spec file and need to add a DLL found in a library. This is right now in my own directory here:
a = Analysis(['eyecommand.py'],
pathex=['.'],
binaries=["C:\users\wwade\appdata\local\programs\python\python39\lib\site-packages\pyvjoy\utils\x64\vJoyInterface.dll"],
datas=added_files,
hiddenimports=["skimage.filters.rank.core_cy_3d","pynput.keyboard._win32", "pynput.mouse._win32"],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=True)
The problem is I don't want to commit that binary line - it will break on anyone else's machine. Is there a way I can "generically" point to the site-packages dir?
%SITEPACKAGES%\pyvjoy\utils\x64\vJoyInterface.dll

You can use the command line switch --collect-binaries <package> if you want to collect dynamic libraries (like the vJoyInterface.dll you specified). The option is available in PyInstaller 4.3 or above.
Referr to your question, there's something similar here -- a function called get_package_paths() which, you can use it like this:
import os
from PyInstaller.utils.hooks import get_package_paths
pyvjoy_ = get_package_paths('pyvjoy')[1]
os.path.join(pyvjoy_, 'utils', 'x64', 'vJoyInterface.dll')
Meanwhile, the pynput hiddenimports was not needed, as a new hook for pynput was added on pyinstaller-hooks-contrib 2021.3 version.

Related

Why is Pyinstaller executable returning error '[19544] Failed to execute script due to unhandled exception!'

I have a Plotly dashboard that I am trying to turn into a executable for distribution. Pyinstaller runs without error but when I try and run the exe I get the following errors (in cmd).
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\Andres\\OneDrive\\Documents\\Automation\\dashboard_tool_v2.0\\dist\\run_dashboard\\dash\\dcc\\package-info.json'
[19544] Failed to execute script 'run_dashboard' due to unhandled exception!
I use the anaconda environment so I've added the following to the spec file to assure it finds all the correct modules. I have also added numpy to the hiddenimports because in the warn-run file it says it is missing a ton of basic numpy functions. you may also see os because I have a second .py file it needs to run and I thought maybe it wasn't reading the imports on that dependency.
a = Analysis(['run_dashboard.py'],
pathex=[('C:\\Users\\Andres\\OneDrive\\Documents\\Automation\\dashboard_tool_v2.0'),
('C:\\users\\Andres\\anaconda3\\lib\\site-packages')],
binaries=[],
datas=added_data,
hiddenimports=['numpy','os'],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
Any idea why it still wont run? it will simply open the python terminal and then close down after a few seconds. Also it might be noteworthy to say I tried to install with --onefile as I have a few .csv files that I want packaged together but then read that this might be an issue so I switched over to --onedir to no avail.

Create an executable from Python code with gmsh import

I'm trying to package up my Python package into an executable using pyinstaller. The script name is called "run-jointbuilder.py" The package has a number of dependancies (such as numpy), but importantly gmsh.
When using pyinstaller to compile my code, it appears to be successful, but then when I try to run the executable I get the following errors:
import gmsh # PyInstaller PYZ\
import ctypes.util # PyInstaller PYZ\
import 'ctypes.util' # <pyimod03_importers.FrozenImporter object at 0x000001BD783FC910>\
Traceback (most recent call last):\
File "PyInstaller\loader\pyiboot01_bootstrap.py", line 144, in __init__
File "ctypes\__init__.py", line 381, in __init__\
FileNotFoundError: Could not find module 'C:\Users\willber\Anaconda3\Scripts\gmsh' (or one of its dependencies). Try using the full path with constructor syntax.
I then get this error:
__main__.PyInstallerImportError: Failed to load dynlib/dll
'C:\\Users\\willber\\Anaconda3\\Scripts\\gmsh'. Most probably this dynlib/dll was not found when the application was frozen.
[18612] Failed to execute script run-jointbuilder
Has anybody tried to compile some Python code that imports the gmsh package? I'd really appreciate an example .spec file, for use with pyinstaller if so!
The gmsh python package wraps a bunch of compiled libraries which contain the implementations of the methods you call from python. When you import gmsh.py into your script then gmsh loads these libraries in the background giving you access to their functionality through python methods. So it's essential that these libraries are embedded in the pyinstaller output for your code to function as it does when you run it directly through the python interpreter.
It's difficult for pyinstaller to consistently find these libraries since they're not accessed in the same way as normal python imports, they are loaded using the cytpes package. There's some description of how pyinstaller does this in the docs. Since you're seeing a dynlib/dll loading error when you run the compiled python script, this suggests that pyinstaller isn't finding the gmsh library during compile and hence it is missing from the executable.
If you look in the gmsh.py source, you can see that gmsh.py loads up a .dll library called gmsh-4.9.dll for Windows OS. You can use the binaries input of the pyinstaller .spec file to point the compiler to the gmsh-4.9.dll.
Here's an example .spec file which dynamically locates the gmsh-4.9.dll at the time of compile so it picks up the right .dll for your active environment. You could make this more generic by filtering all *.dll in the gmsh directory, but I've hardcoded for clarity:
# -*- mode: python ; coding: utf-8 -*-
from pathlib import Path
import gmsh
# get the location of the gmsh dll which sits next to the gmsh.py file
libname = 'gmsh-4.9.dll'
libpath = Path(gmsh.__file__).parent / libname
print('Adding {} to binaries'.format(libpath))
block_cipher = None
a = Analysis(['gmsh-test.py'],
pathex=['C:\\Users\\user\\dev\\gmsh'],
# tell pyinstaller to add the binary to the compiled path
binaries=[(str(libpath), '.')],
datas=[],
hiddenimports=[],
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='gmsh-test',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True,
runtime_tmpdir=None,
)

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"

Python executable created with PyInstaller doesn't run

I have a simple script in order to plot a ROC curve (using sklearn and matplotlib). I used PyInstaller to create an executable from this script. The script itself runs and works perfectly but the executable gives me this error:
No module named 'tkinter'
What I tried:
1) Re-create the executable without the --onefile flag (in case any .dll was missing) (FAILED)
2) Manually import tkinter inside my script (FAILED)
Actually when I added import tkinter the error changed to (in case it matters):
No module named 'tkinter.filedialog'
I am confused. I used PyInstaller many times but it's the first time I encounter this kind of error.
Edit the .spec file and put the path to the module inside 'pathex' (on Analysis). You can discover the correct module path using module.__file__.
In your case:
>>> import tkinter.filedialog
>>> tkinter.filedialog.__file__
'/usr/lib/python3.5/tkinter/filedialog.py'
On .spec file:
a = Analysis(['main.py'],
pathex=['/usr/lib/python3.5/tkinter/'],
binaries=None,
datas=None,
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)

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, ...]

Categories

Resources