alejandroautalan/pygubu

Why not use pkgutil for resource loading?

D0m0 opened this issue · 7 comments

D0m0 commented

Pygubu is an ingenious tool that I discovered only now, although I use tkinter for at least 2 years! It's a professionally developed solid piece of code. I tried it and it works as intended out of the box!

I often put my project in a zip file, rename it to .pyz, and it becomes a single-file cross-platform app (which often only needs python3 installed). To load resources in such an app I use pkgutil.get_data(), which is nice because it works both ways: from a pyz-file and from the original unpacked app while I debug it. And pkgutil is a standard library.

So, when I use Pygubu I can load .ui files using builder.add_from_string(pkgutil.get_data(PROJECT_MODULE, PROJECT_UI)), but if I use images inside the .ui file, they are not being loaded.

I understand that Pygubu is adapted for use with PyInstaller and several other packagers, but maybe using pkgutil.get_data() will simplify all this resource-loading? Or maybe I'm doing something wrong?

Thanks!

Hello @D0m0, thanks for trying pygubu. I'm glad that it is useful to you.

I will investigate pkgutil and find a solution for this case.

Regards
Alejandro A.

Hello @D0m0, can you provide a little example application so I can see how do you setup PROJECT_MODULE and PROJECT_UI variables?

Regards
Alejandro A.

D0m0 commented

Hi! Here's my sample project:

project
├── __main__.py
├── dist
│   └── gubu.pyz        <--- zip, contains the whole project folder
└── ui
    ├── __init__.py
    ├── pygubu-test.ui  <--- contains references to *.gif
    ├── red.gif
    ├── green.gif
    └── yellow.gif

main.py

#!/usr/bin/env python3

from pkgutil import get_data
import pathlib
import tkinter as tk
from tkinter import messagebox
import tkinter.ttk as ttk
import pygubu

PROJECT_PATH = pathlib.Path(__file__).parent
PROJECT_UI = 'pygubu-test.ui'

class HelloWorldApp:
	def __init__(self, master=None):
		self.builder = builder = pygubu.Builder()
		builder.add_resource_path(PROJECT_PATH)
		builder.add_from_string(get_data('ui', PROJECT_UI))
		self.mainwindow = builder.get_object('toplevel1', master)
		builder.connect_callbacks(self)

	def on_button_browse_ac(self):
		messagebox.showinfo(title="Message", message="DhAJsja1!", parent=self.mainwindow)

if __name__ == '__main__':
	print(PROJECT_PATH)
	print(__file__)
	app = HelloWorldApp()
	app.mainwindow.mainloop()
D0m0 commented

When I launch main.py, it works as expected, printing these values:

.                 # PROJECT_PATH
./__main__.py     # __file__

When I run dist/gubu.pyz, it works too (but without images), printing these values:

dist/gubu.pyz                 # PROJECT_PATH
dist/gubu.pyz/__main__.py     # __file__

gubu.pyz is a .zip file with a shebang header like this: #!/usr/bin/env python3
It works in Windows and Linux, as long as python3+tk is installed (I also put the pygubu folder in the zip file).

My theory is that using pkgutil.get_data() can extract resources in any case, maybe even when using PyInstaller etc. But I could be wrong, and I didn't test that. Tell me if you need help testing this.

Thanks. One more question, which python version are You using?

D0m0 commented

I'm using versions 3.6.2, 3.7.5, 3.9. I don't mind if you ditch the oldest versions!

Hello @D0m0.

It seems that the recommended approach is to use the importlib.resources module.

I have been working with that in mind. I have created an example of use here.

If you can, test it with your projects installing pygubu from the github repositories with:

pip install git+https://github.com/alejandroautalan/pygubu git+https://github.com/alejandroautalan/pygubu-designer

If you have any suggestions let me know.

Regards
Alejandro A.