I am using PySide6 and pygraphviz to create a simple three widget desktop application. When I use pyinstaller --onefile --noconsole stackedAPP.py
, PyInstaller throws me this error: Unable to find '/usr/sbin/neato' when adding binary and data files.
It seems that PyInstaller cannot find any of the pygraphviz layouts, not just neato because I tried using other layouts too. This is not an isolated issue, as I found in this older post, but there was no answer so I had to ask again.
A similar PyInstaller error here seemed to have been resolved after modifying the hooks for the package, so I tried to look into hook-pygraphviz.py.
It seemed to me that the error lies in the line: graphviz_bindir = os.path.dirname(os.path.realpath(shutil.which("dot")))
which returns /usr/sbin
Upon further investigation, I found that shutil.which('dot')
returns /usr/bin/dot
which is actually correct (having manually confirmed it). But the result of os.path.realpath('/usr/bin/dot')
is actually something else entirely:
>>> import os
>>> import shutil
>>> shutil.which("dot")
'/usr/bin/dot'
>>> os.path.realpath('/usr/bin/dot')
'/usr/sbin/libgvc6-config-update'
So the reason why PyInstaller cannot find neato in /usr/sbin is because it is not in /usr/sbin, and this is why it is searching in /usr/sbin in the first place.
So I decided to manually modify the hook and set the path as graphviz_bindir = '/usr/bin'
This helped and PyInstaller compiled successfully, but when I use the application, it crashes when it enters the stage where it is using pygraphviz and this is the error message I see:
(stackedAPP:18070): GLib-GIO-CRITICAL **: 22:02:47.490: GFileInfo created without standard::icon
(stackedAPP:18070): GLib-GIO-CRITICAL **: 22:02:47.490: file ../../../gio/gfileinfo.c: line 1766 (g_file_info_get_icon): should not be reached
Traceback (most recent call last):
File "processUI.py", line 127, in on_finished
File "processUI.py", line 189, in generate_causal_loop_diagram
File "pygraphviz/agraph.py", line 1613, in draw
File "pygraphviz/agraph.py", line 1404, in _run_prog
OSError: Warning: Could not load "/tmp/_MEIsRtebz/graphviz/libgvplugin_pango.so.6" - file not found
Warning: Could not load "/tmp/_MEIsRtebz/graphviz/libgvplugin_pango.so.6" - file not found
Warning: Could not load "/tmp/_MEIsRtebz/graphviz/libgvplugin_pango.so.6" - file not found
Warning: Could not load "/tmp/_MEIsRtebz/graphviz/libgvplugin_pango.so.6" - file not found
Warning: Could not load "/tmp/_MEIsRtebz/graphviz/libgvplugin_gd.so.6" - file not found
Format: "png" not recognized. Use one of: bmp canon cmap cmapx cmapx_np dot dot_json eps fig gd gd2 gif gtk gv ico imap imap_np ismap jpe jpeg jpg json json0 mp pdf pic plain plain-ext png pov ps ps2 svg svgz tif tiff tk vdx vml vmlz vrml wbmp webp x11 xdot xdot1.2 xdot1.4 xdot_json xlib
I'm not sure how to proceed from here. I am using VirtualBox to run Ubuntu-23.10 on which I am running this process. When I installed graphviz and pygraphviz I used:
sudo apt-get graphviz graphviz-dev
pip install pygraphviz
as recommended in this documentation. Any help would be greatly appreciated!
One workaround I found to just get an application is to use cx_freeze
I ran cxfreeze -c translator.py --target-dir dist
and got an application that runs without any errors. I'll have to take a look how cx_Freeze does things differently from PyInstaller.
It's also possible to use pyinstaller, but I had to modify hooks/stdhooks/hook-pygraphviz.py
slightly. I modified the line graphviz_bindir = os.path.dirname(os.path.realpath(shutil.which("dot")))
to graphviz_bindir = shutil.which('dot')
and added dynamic graphviz libs by locating where graphviz was and then using --add-binary argument from pyinstaller. For me it was something like pyinstaller --onefile --add-binary /usr/lib/x86_64-linux-gnu/graphviz:graphviz main.py
.