Home > Software design >  app packed with pyinstaller don't open file from temporary directory (tkinter, tksvg, tempfile)
app packed with pyinstaller don't open file from temporary directory (tkinter, tksvg, tempfile)

Time:10-26

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

  • Related