Repository: pyinstaller/pyinstaller

Issue:
Unable to run PyQt program after building successfully
I'm writing a PyQt5.9 application and since I'm almost done I was trying out PyInstaller, but for some reason I cannot figure this out.

I am able to replicate the issue I have with a simpler "helloworld" app; it gives the same error as when I build/run my actual application.

_Does the error occur when bundling the application or when running it?_

When running it.

_If you have an import error, please submit the last part of the traceback. This helps a lot to see which modules tried to import which other one._

There is no import error.

_Is there anything striking in the debug-output?_

Yes there is:

```
 $    QT5DIR=/opt/Qt/5.9.1/gcc_64 pyinstaller --debug hello.py
20 INFO: PyInstaller: 3.3.dev0+89dc7ebce
20 INFO: Python: 3.5.3
21 INFO: Platform: Linux-4.9.0-3-amd64-x86_64-with-debian-9.0
21 INFO: wrote /local/pyqt5-projects/helloworld/hello.spec
22 INFO: UPX is not available.
23 INFO: Extending PYTHONPATH with paths
['/local/pyqt5-projects/helloworld', '/local/pyqt5-projects/helloworld']
23 INFO: checking Analysis
23 INFO: Building Analysis because out00-Analysis.toc is non existent
23 INFO: Initializing module dependency graph...
23 INFO: Initializing module graph hooks...
24 INFO: Analyzing base_library.zip ...
1954 INFO: running Analysis out00-Analysis.toc
1970 INFO: Caching module hooks...
1972 INFO: Analyzing /local/pyqt5-projects/helloworld/hello.py
1986 INFO: Loading module hooks...
1986 INFO: Loading module hook "hook-xml.py"...
2139 INFO: Loading module hook "hook-pydoc.py"...
2139 INFO: Loading module hook "hook-encodings.py"...
2174 INFO: Loading module hook "hook-PyQt5.QtQuick.py"...
2235 INFO: Loading module hook "hook-PyQt5.QtQml.py"...
2235 INFO: Loading module hook "hook-PyQt5.py"...
2235 INFO: Loading module hook "hook-PyQt5.Qt.py"...
2236 INFO: Loading module hook "hook-PyQt5.QtWidgets.py"...
2236 INFO: Loading module hook "hook-PyQt5.QtCore.py"...
2260 INFO: Loading module hook "hook-PyQt5.QtPrintSupport.py"...
2282 INFO: Loading module hook "hook-PyQt5.QtNetwork.py"...
2305 INFO: Loading module hook "hook-PyQt5.QtGui.py"...
2462 INFO: Looking for ctypes DLLs
2462 INFO: Analyzing run-time hooks ...
2464 INFO: Including run-time hook 'pyi_rth_qml.py'
2465 INFO: Including run-time hook 'pyi_rth_qt5.py'
2466 INFO: Including run-time hook 'pyi_rth_qt5plugins.py'
2469 INFO: Looking for dynamic libraries
3471 INFO: Looking for eggs
3471 INFO: Python library not in binary dependencies. Doing additional searching...
3500 INFO: Using Python library /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
3502 INFO: Warnings written to /local/pyqt5-projects/helloworld/build/hello/warnhello.txt
3521 INFO: checking PYZ
3522 INFO: Building PYZ because out00-PYZ.toc is non existent
3522 INFO: Building PYZ (ZlibArchive) /local/pyqt5-projects/helloworld/build/hello/out00-PYZ.pyz
3717 INFO: Building PYZ (ZlibArchive) /local/pyqt5-projects/helloworld/build/hello/out00-PYZ.pyz completed successfully.
3718 INFO: checking PKG
3718 INFO: Building PKG because out00-PKG.toc is non existent
3718 INFO: Building PKG (CArchive) out00-PKG.pkg
3745 INFO: Building PKG (CArchive) out00-PKG.pkg completed successfully.
3747 INFO: Bootloader /local/virtualenvs/priceplan-generator/lib/python3.5/site-packages/PyInstaller/bootloader/Linux-64bit/run
3747 INFO: checking EXE
3747 INFO: Building EXE because out00-EXE.toc is non existent
3747 INFO: Building EXE from out00-EXE.toc
3748 INFO: Appending archive to ELF section in EXE /local/pyqt5-projects/helloworld/build/hello/hello
3751 INFO: Building EXE from out00-EXE.toc completed successfully.
3753 INFO: checking COLLECT
3753 INFO: Building COLLECT because out00-COLLECT.toc is non existent
3753 INFO: Building COLLECT out00-COLLECT.toc
3988 INFO: Building COLLECT out00-COLLECT.toc completed successfully.
```

```
 $    ./dist/hello/hello
QQmlApplicationEngine failed to load component
file:///local/pyqt5-projects/helloworld/hello.qml:27 Type ApplicationWindow unavailable
file:///local/pyqt5-projects/helloworld/dist/hello/qml/QtQuick/Controls.2/ApplicationWindow.qml:-1 No such file or directory
```

_version of Python_
```
 $    python --version
Python 3.5.3
```

_exact version of PyInstaller_

Since the latest on PyPI didn't work I've installed a version directly from github.

```
 $    pyinstaller --version
3.3.dev0+89dc7ebce
```

_exact version of the 3rd-party module trapping the error_

I'm imagining you mean PyQt5 ?

```
 $    pip freeze | grep PyQt5
PyQt5==5.9
```

I also installed Qt on my computer to be able to use qtcreator. The installer is called `qt-unified-linux-x64-3.0.0-online.run`

_For Linux please specify the distribution and version_

Debian 9.0

_A minimal example program which shows the error._

hello.qml

```
import QtQuick 2.4
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.1


ApplicationWindow {
    title: qsTr("Window")
    Rectangle {
        width: 360
        height: 360
        Text {
            anchors.centerIn: parent
            text: "Hello World"
        }
        MouseArea {
            anchors.fill: parent
            onClicked: {
                Qt.quit();
            }
        }
    }
}
```

hello.py

```
import sys


from PyQt5 import QtWidgets, QtQml


# Do this import for the pyinstaller PyQt.Quick hook.
from PyQt5 import QtQuick  # noqa


def main():
    app = QtWidgets.QApplication(sys.argv)
    engine = QtQml.QQmlApplicationEngine()
    engine.load('hello.qml')
    root = engine.rootObjects()[0]
    root.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
```

_Did you try implementing a hook or run-time-hook (rthook) to solve the problem? If so, please include the hook file._

I did not, because I assume this _should_ work with existing PyQt hooks.

_Please make sure to attach the log output generated by PyInstaller_

https://gist.github.com/cpoppema/beb2f816a4e903d5123d7a77c6c4e175 contains the output of the following command:

```
QT5DIR=/opt/Qt/5.9.1/gcc_64 pyinstaller hello.py --log-level DEBUG > out.txt 2>&1
```


Discussion:

Resolving patch:
diff --git a/PyInstaller/hooks/hook-PyQt5.QtQuick.py b/PyInstaller/hooks/hook-PyQt5.QtQuick.py
--- a/PyInstaller/hooks/hook-PyQt5.QtQuick.py
+++ b/PyInstaller/hooks/hook-PyQt5.QtQuick.py
@@ -16,6 +16,7 @@
                  ]
 
 from PyInstaller.utils.hooks import (
+    qt5_qml_dir,
     qt5_qml_data,
     qt5_qml_plugins_binaries,
     qt5_qml_plugins_datas
@@ -33,14 +34,16 @@
         #'QtTest'
         ]
 
+qmldir = qt5_qml_dir('PyQt5')
+
 # Add base qml directories
-datas = [qt5_qml_data(dir) for dir in dirs]
+datas = [qt5_qml_data(qmldir, dir) for dir in dirs]
 
 # Add qmldir and *.qmltypes files
 for dir in dirs:
-    datas.extend(qt5_qml_plugins_datas(dir))
+    datas.extend(qt5_qml_plugins_datas(qmldir, dir))
 
 # Add binaries
 binaries = []
 for dir in dirs:
-    binaries.extend(qt5_qml_plugins_binaries(dir))
+    binaries.extend(qt5_qml_plugins_binaries(qmldir, dir))
diff --git a/PyInstaller/hooks/hook-PySide2.QtQuick.py b/PyInstaller/hooks/hook-PySide2.QtQuick.py
--- a/PyInstaller/hooks/hook-PySide2.QtQuick.py
+++ b/PyInstaller/hooks/hook-PySide2.QtQuick.py
@@ -8,6 +8,7 @@
 #-----------------------------------------------------------------------------
 
 from PyInstaller.utils.hooks import (
+    qt5_qml_dir,
     qt5_qml_data,
     qt5_qml_plugins_binaries,
     qt5_qml_plugins_datas
@@ -31,15 +32,17 @@
         # 'QtTest'
         ]
 
+qmldir = qt5_qml_dir('PySide2')
+
 # Add base qml directories
-datas = [qt5_qml_data(dir) for dir in dirs]
+datas = [qt5_qml_data(qmldir, dir) for dir in dirs]
 
 # Add qmldir and *.qmltypes files
 for dir in dirs:
-    datas.extend(qt5_qml_plugins_datas(dir))
+    datas.extend(qt5_qml_plugins_datas(qmldir, dir))
 
 # Add binaries
 binaries = []
 for dir in dirs:
-    binaries.extend(qt5_qml_plugins_binaries(dir))
+    binaries.extend(qt5_qml_plugins_binaries(qmldir, dir))
     import pprint
diff --git a/PyInstaller/utils/hooks/qt.py b/PyInstaller/utils/hooks/qt.py
--- a/PyInstaller/utils/hooks/qt.py
+++ b/PyInstaller/utils/hooks/qt.py
@@ -175,7 +175,16 @@ def get_qmake_path(version=''):
     return None
 
 
-def qt5_qml_dir():
+def qt5_qml_dir(namespace):
+    if namespace not in ['PyQt5', 'PySide2']:
+        raise Exception('Invalid namespace: {0}'.format(namespace))
+
+    if namespace == 'PyQt5':
+        import PyQt5
+        qmldir = os.path.join(PyQt5.__path__[0], 'Qt', 'qml')
+        if os.path.isdir(qmldir):
+            return qmldir
+
     qmake = get_qmake_path('5')
     if qmake is None:
         qmldir = ''
@@ -194,20 +203,18 @@ def qt5_qml_dir():
     return qmldir
 
 
-def qt5_qml_data(directory):
+def qt5_qml_data(qmldir, directory):
     """
     Return Qml library directory formatted for data.
     """
-    qmldir = qt5_qml_dir()
     return os.path.join(qmldir, directory), os.path.join('qml', directory)
 
 
-def qt5_qml_plugins_binaries(directory):
+def qt5_qml_plugins_binaries(qmldir, directory):
     """
     Return list of dynamic libraries formatted for mod.binaries.
     """
     binaries = []
-    qmldir = qt5_qml_dir()
 
     qt5_qml_plugin_dir = os.path.join(qmldir, directory)
     files = misc.dlls_in_subdirs(qt5_qml_plugin_dir)
@@ -222,12 +229,11 @@ def qt5_qml_plugins_binaries(directory):
     return binaries
 
 
-def qt5_qml_plugins_datas(directory):
+def qt5_qml_plugins_datas(qmldir, directory):
     """
     Return list of data files for mod.binaries. (qmldir, *.qmltypes)
     """
     datas = []
-    qmldir = qt5_qml_dir()
 
     qt5_qml_plugin_dir = os.path.join(qmldir, directory)
 


Test patch: