Qt.py icon indicating copy to clipboard operation
Qt.py copied to clipboard

Issue when running pyinstaller generated .exe

Open tobkum opened this issue 4 years ago • 8 comments

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!

tobkum avatar Jan 02 '20 05:01 tobkum

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.

mottosso avatar Jan 02 '20 06:01 mottosso

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 = PySide2 suggestion as soon as I get back home.

tobkum avatar Jan 02 '20 13:01 tobkum

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.

mottosso avatar Jan 02 '20 18:01 mottosso

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

tobkum avatar Jan 02 '20 21:01 tobkum

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

aspartamed avatar Apr 02 '20 14:04 aspartamed

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 avatar Feb 10 '21 03:02 cmcpasserby

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.

cmcpasserby avatar Feb 12 '21 15:02 cmcpasserby

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

csmotion avatar Feb 23 '22 16:02 csmotion