Hi everyone I have a problem with a simple app (at least the MRE is simple) packed with pyinstaller. This desktop app should display a simple SVG file (I use tksvg). My app first writes SVG into a temporary directory (writing is not as simple as in MRE), and then in the right moment displays it. It works nicely until I've packed it with pyinstaller. My full app console throws me an error that the file can't be found. The path always ends with \tksvg. And such directory don't exist. It looks as if tksvg would create such a subfolder but pyinstaller is missing such instructions? Any ideas on what can I do? Warning, total noob. Thanks
from tkinter import *
import tempfile
import tksvg
root = Tk()
temp_dir = tempfile.TemporaryDirectory()
print(temp_dir.name)
with open(temp_dir.name f'\\test.svg', 'w') as a_file:
a_file.write('<svg viewBox="0 0 400 400"><rect x="0" y="0" width="400" height="400" fill="red" /></svg>')
svg_image = tksvg.SvgImage(file=temp_dir.name f'\\test.svg')
show_svg = Label(root, image=svg_image)
show_svg.pack()
mainloop()
Edit
After some fight with the subject, I'm certain that it must be an issue with how pyinstaller packs libraries, a specially tksvg. Method proposed by @JRiggles in itself works, but not with tksvg objects, and it's not necessary in my case (I use a temporary directory to manage files). To check if the temporary directory works also when packed (pyinstaller), I've created "jpeg viewer" script and it works perfectly, even using PIL libraries.
from tkinter import *
import tempfile
from tkinter import filedialog
from PIL import Image, ImageTk
root = Tk()
temp_dir = tempfile.TemporaryDirectory()
print(temp_dir.name) # just to check if temp. dir. was created
jpeg_file = filedialog.askopenfilename(filetypes=[("jpeg file", "*.jpeg")]) # opening file from disc
picture = Image.open(jpeg_file) # reading it with PIL library
picture.save(temp_dir.name '\\test.jpeg') # saving image to temp. dir.
an_image = Image.open(temp_dir.name '\\test.jpeg') # opening image from temp.dir.
the_image = ImageTk.PhotoImage(an_image) # reading image
show_image = Label(root, image=the_image) # setting label as "display"
show_image.pack() # showing the image
mainloop()
Does anyone has experience with SVG libraries, tksvg or any other, and how to make exe. with them?
CodePudding user response:
Pyinstaller places your assets (images, icons, whatever) in a special directory that's created in your temp dir at runtime. I use this fetch_resource
function to dynamically load assets when running a pyinstaller executable
import sys
from pathlib import Path
def fetch_resource(rsrc_path):
"""Loads resources from the temp dir used by pyinstaller executables"""
try:
base_path = Path(sys._MEIPASS)
except AttributeError:
return rsrc_path # not running as exe, just return the unaltered path
else:
return base_path.joinpath(rsrc_path)
In your case, you would use it like so:
svg_path = fetch_resource(r'path\to\test.svg')
with open(svg_path, 'w') as a_file:
...
svg_image = tksvg.SvgImage(file=svg_path)
You'll need to tell pyinstaller where to locate any files you want to 'fetch' by using the --add-data
command-line or by adding the path to the datas
list in your *.spec
file
CodePudding user response:
After some time it turn out that it was enough to add --collect-all="tksvg" to the pyinstaller. Maybe you could be more specific about what was missing in the compiled pack, but I have no competence to judge it, so I went for a safe collect-all. THX