achille-martin / pyqt-crom

Create cross-platform apps (Android for now) using only Python and the Qt Framework (PyQt5 for now).
MIT License
29 stars 2 forks source link

Bug: cannot add more py files and non-python files to the package read by the pdt #41

Open mrRaduga opened 5 months ago

mrRaduga commented 5 months ago

Hi @achille-martin

When I am trying to deploy an application created with more than one .py file, the .apk isn't running on Android. For the example you can see the followig structure:

image

And of course, the config.ptd file:

image

I think that the files are not collecting correct by the building tool, can you try by yourself and come with a feedback?

achille-martin commented 5 months ago

There is something tricky around python packages and Android filesystem that I have not fully understood yet.

There is work in progress in the background to get this to function fine, but focus at the moment is on this issue (with a single file).

The workaround (for now) is to create all extra python package files from a unique python script. Cf. this script for example.

Not ideal, but I'll get back to this issue.

Thanks for your contribution.

mrRaduga commented 5 months ago

Unfortunately, there are too many files to fit everything into one script 😢

The same problem exists with resources like images, icons, etc. I think this is also related to the Android file system.

I will also do some research and provide you with any information I have.

achille-martin commented 5 months ago

No worries, there might be something we have missed.

Interestingly enough, I was looking at the issue I mentioned and I managed to access resources from within the built "pyqt5 android" package.

There is an example here (the whole external_python_project_2 folder actually) if you are curious. It is using importlib.resources to access resources from within the package and it seems to be the python standard to do so. Note that only importlib.resources.read_text() is properly working. I still need to investigate how to get yaml to read a file within the package, but there is potential there!

achille-martin commented 4 months ago

I have created a very basic package that can be read by the pdt -> Link.

At the moment, it is only composed of a config file and a python module, but it works on Android through importlib.resources. Note that it also works on Linux.

I'll update into a more comprehensive package, but you can give it a try and get the inspiration for your own package.

mrRaduga commented 4 months ago

Servus @achille-martin

I'm trying to load images into an application based on your externalpy example project. You can find the changes I made to the pyqt5_app_with_yaml.py file below:

        # Initialise Layout
        self.layout = QHBoxLayout()
        self.layout.setSpacing(10)
        self.layout.setContentsMargins(10, 10, 10, 10)
        self.setLayout(self.layout)

        # Initialise image
        img_label = QLabel(self)
        pixmap = QtGui.QPixmap()
        self.img_path = None

        try:
            logger.debug(f"""MainWindow::__init__ - Getting file path and file itself img.png""")
            with resources.path(validate_pkg_format('externalpy_pkg.resources', logger), 'img.png') as path:
                self.img_path = realpath(path)
                logger.debug(f"""MainWindow::__init__ - Obtained file path for img.png: {self.img_path}""")
            logger.debug(f"MainWindow::__init__ - Obtained file path: {self.img_path}")
        except Exception as e:
            logger.warn(f"""MainWindow::__init__ - Exception caught for img.png: {e}""")

        if not isfile(self.img_path):
            logger.debug(f"""MainWindow::__init__ - Cannot import img.png file from `{self.img_path}` Because file does not exist""")
            img_label.setText('No image founded.')
        else:
            pixmap.load(self.img_path)
            pixmap = pixmap.scaledToWidth(100)
            img_label.setPixmap(pixmap)
            logger.debug(f"""MainWindow::__init__ - Imported img.png file from `{self.img_path}`.""")
        self.layout.addWidget(img_label)

So, I expected it to work, but unfortunately it didn't.

Android application logs are given below:

[2024-05-21 11:38:39,116] [DEBUG] - MainWindow::__init__ - Getting file path and file itself img.png
[2024-05-21 11:38:39,117] [DEBUG] - validation_tools::validate_pkg_format - Received request to validate: externalpy_pkg.resources
[2024-05-21 11:38:39,117] [DEBUG] - validation_tools::validate_pkg_format - Generated joined package name: externalpy_pkg/resources
[2024-05-21 11:38:39,118] [DEBUG] - validation_tools::validate_pkg_format - Found joined package name
[2024-05-21 11:38:39,118] [DEBUG] - validation_tools::validate_pkg_format - Returning package name: externalpy_pkg/resources
[2024-05-21 11:38:39,157] [DEBUG] - MainWindow::__init__ - Obtained file path for img.png: /data/user/0/org.qtproject.example.ExternalPyApp/files/tmpw_qg4e34img.png
[2024-05-21 11:38:39,160] [DEBUG] - MainWindow::__init__ - Obtained file path: /data/user/0/org.qtproject.example.ExternalPyApp/files/tmpw_qg4e34img.png
[2024-05-21 11:38:39,160] [DEBUG] - MainWindow::__init__ - Cannot import img.png file from `/data/user/0/org.qtproject.example.ExternalPyApp/files/tmpw_qg4e34img.png` Because file does not exist

The resource directory looks like this:

image

I have no idea what's wrong

achille-martin commented 4 months ago

@mrRaduga,

with resources.path(validate_pkg_format('externalpy_pkg.resources', logger), 'img.png') as path: is a ContextManager more info here.

Therefore, the file is only accessible within the with ... block. Once you exit the block, the resource is "destroyed" (not accessible anymore).

So I would suggest that you move your condition checks if not isfile(self.img_path): into the with ... block. Basically, under this line: logger.debug(f"""MainWindow::__init__ - Obtained file path for img.png: {self.img_path}""").

Let me know if that does the trick!