alejandroautalan / pygubu

A simple GUI builder for the python tkinter module
MIT License
2.01k stars 213 forks source link

Why not use pkgutil for resource loading? #269

Closed D0m0 closed 1 year ago

D0m0 commented 1 year ago

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!

alejandroautalan commented 1 year ago

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.

alejandroautalan commented 1 year ago

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 1 year ago

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 1 year ago

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.

alejandroautalan commented 1 year ago

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

D0m0 commented 1 year ago

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

alejandroautalan commented 1 year ago

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.