mottosso / Qt.py

Minimal Python 2 & 3 shim around all Qt bindings - PySide, PySide2, PyQt4 and PyQt5.
MIT License
908 stars 254 forks source link

Issue when running pyinstaller generated .exe #332

Open tobkum opened 4 years ago

tobkum commented 4 years ago

I'm having an issue with Qt.py in conjunction with pyinstaller. When trying to run the frozen .exe, I get an "ImportError: cannot import name 'QtWidgets' from 'Qt' (E:\xxxx\Qt.pyc)" - (xxxx replacing the path). That pyc file mentioned in the error doesn't exist. Do I have to use hidden imports when freezing an application with Qt.py or what seems to be the issue here? Thanks!

mottosso commented 4 years ago

That's an interesting problem. Can you confirm it has access to a binding? E.g. your program should be able to call import PyQt5 or PySide etc. depending on which one you use.

It was a while since I worked with pyinstaller, so I'm not sure what hidden imports do. But at the end of the day, Qt.py is importing a binding like PyQt5 and creating its inner namespaces - such as QtWidgets - from that.

If what you use/bundle is PySide2, then you may perhaps be so bold as to simply say Qt = PySide2 after having imported it, as Qt.py follows the same API, with the only exception being the added QtCompat submodule.

tobkum commented 4 years ago

Some more info - I'd like to write a desktop application, using PySide2 under the LGPL terms, which means (among other things) I have to give the user the ability to replace the bundled PySide2 version with his/her own. I was looking into Qt.py for that reason, so my own code doesn't even mention a specific PySide version, and let Qt.Py handle that part. This works fine when running from a .py file, but somehow breaks when freezing the application via pyinstaller. Since you're saying it's been a while since you used pyinstaller, you don't happen to know a way to distribute a frozen application that uses Qt.py and - at runtime - imports the vendored Pyside2, or if the user provides his own PySide2 version, imports that one instead?

I'll try the Qt = PySide2suggestion as soon as I get back home.

mottosso commented 4 years ago

This works fine when running from a .py file, but somehow breaks when freezing the application via pyinstaller.

From what I understand, this is by design. The freezing process is meant to remove any dependency on the source system, the Python distribution and any libraries. As far as I understand, your frozen application isn't exposed to the same sys.path or PYTHONPATH as the original Python application.

But I would be surprised if you couldn't circumvent this; e.g. if the user installed PySide2 at c:\SomeDir\PySide2, then you should be able to - from within your application - say sys.path.insert(0, r"c:\SomeDir") followed by import PySide2.

If so, then you should also find that from Qt import QtWidgets should work too, since that's effectively what it's doing under the hood.

tobkum commented 4 years ago

Hah, good point you got there. I'll check that asap and report back. Cheers!

aspartamed commented 4 years ago

I am having a similar issue getting Qt.py to work with pyinstaller, I wrote up a simple helloworld example and am trying to get answers on stackoverflow below, I would appreciate any help in understnading how to generate an exe with pyinstaller. My tests show if I just replace Wt with Pyside2 then I can build the exe but I dont want to have to modify my source to build a distribution. https://stackoverflow.com/questions/60977939/pyinstaller-creating-a-standalone-executable-that-uses-qt-py/60979774#60979774

cmcpasserby commented 3 years ago

You just have to add PySide2 modules as hidden imports in the PyInstaller spec file then its all fine. In my spec file i just set hiddenimports to be hiddenimports=["PySide2.QtWidgets", "PySide2.QtGui", "PySide2.QtCore", "PySide2.QtOpenGL"] if you only add PySide2 it wont work since its just a package not a module, and it does not support wildcards so cant use PySide2.*

cmcpasserby commented 3 years ago

It might be possible to avoid this problem by adding PyInstaller Hooks to this package. If there is interests I could look at making a PR for it.

csmotion commented 2 years ago

Howdy @cmcpasserby and @tobkum. I'm also interested in using Qt.py with PyInstaller to satisfy the PySide2 LGPL terms. What is the current process for using Qt.py to import a vendored QT binding at runtime? I saw the hook below, but I'm a little unclear on usage.

https://github.com/pyinstaller/pyinstaller/blob/develop/PyInstaller/utils/hooks/qt.py