QtWidgets.QApplication(sys.argv)之后不能导入PyQt模块

时间:2022-07-01 03:50:14

OVERVIEW

概述

I'm having troubles importing modules after the line QtWidgets.QApplication(sys.argv), let's say I got this little snippet main.py:

在代码行QtWidgets.QApplication(sys.argv)之后,我在导入模块时遇到了麻烦,假设我得到了这个小代码片段main.py:

import sys
import importlib
from PyQt5 import QtWidgets

print('Sys Path:')
print('  %s\n' % '\n  '.join(sys.path))

if sys.argv[-1] == '1':
    print('Importing Before...\n')
    from PyQt5 import Qt
    app = QtWidgets.QApplication(sys.argv)

elif sys.argv[-1] == '2':
    print('Importing After...\n')
    app = QtWidgets.QApplication(sys.argv)
    from PyQt5 import Qt

print('Done')
  • If I run python main.py 1 everything works as expected.
  • 如果我运行python main。py 1一切正常。
  • If I run python main.py 2 the process hangs (probably in a infinite loop) without giving any error.
  • 如果我运行python main。py 2进程挂起(可能在无限循环中),不会产生任何错误。

Output of python main.py 2:

python的主要输出。py 2:

(py352) D:\sources\personal\python\pyqt\mcve>python main.py 2           
Sys Path:                                                               
  D:\sources\personal\python\pyqt\mcve                                  
  D:\sources\personal\python                                            
  d:\virtual_envs\py352\Scripts\python35.zip                            
  d:\virtual_envs\py352\DLLs                                            
  d:\virtual_envs\py352\lib                                             
  d:\virtual_envs\py352\Scripts                                         
  c:\Python352\Lib                                                      
  c:\Python352\DLLs                                                     
  d:\virtual_envs\py352                                                 
  d:\virtual_envs\py352\lib\site-packages                               

Importing After...                                                      
(HANG)

ATTEMPTS

尝试

Tested with a couple of virtualenvs on win7:

在win7上测试了几个虚拟人物:

  • Python 3.5.1 (v3.5.1:37a07cee5969, Dec 6 2015, 01:54:25) [MSC v.1900 64 bit (AMD64)] on win32 on win7
  • Python 3.5.1 (v3.5.1:37a07cee5969, 2015年12月6日01:54:25)[MSC v.]在win32上,win7上
  • Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 25 2016, 22:01:18) [MSC v.1900 32 bit (Intel)] on win32
  • Python 3.5.2 (v3.5.2:4def2a2901a5, 2016年6月25日22:01:18)[MSC v.]193bit(英特尔)]win32

Pyqt was installed on the virtualenvs using pip and the versions are these ones:

Pyqt安装在virtualenv上,使用pip和版本是这些:

>>> QtCore.QT_VERSION
329472
>>> QtCore.QT_VERSION_STR
'5.7.0'
>>> QtCore.PYQT_VERSION_STR
'5.7'

RELEVANT INFORMATION

相关信息

Some very nice people from #pyqt freenode channel helped me to test the repo and none of them were able to reproduce the issue, the python versions and platforms they used were:

一些来自#pyqt freenode通道的非常好的人帮助我测试了repo,他们没有一个能够复制这个问题,他们使用的python版本和平台是:

  • win10 - 3.5.2 |Anaconda 4.1.1 (64-bit)
  • win10 - 3.5.2 |Anaconda 4.1.1(64位)
  • win8 - 3.5.2 (v3.5.2:4def2a2901a5, Jun 25 2016, 22:01:18)
  • win8 - 3.5.2 (v3.5.2:4def2a2901a5, 2016年6月25日22:01:18)
  • ubuntu 16.04 - 3.5.2 (default, Nov 17 2016, 17:05:23)
  • ubuntu 16.04 - 3.5.2(默认,2016年11月17日,17:05:23)

QUESTIONS

问题

  • What's the reason of from PyQt5 import Qt (or others pyqt modules) getting stuck on my box and other people not being able to reproduce?
  • PyQt5导入Qt(或其他pyqt模块)卡在我的盒子上而其他人无法复制的原因是什么?
  • How can I fix this behaviour? This is important to me cos I'd like to load plugins dynamically once my pyqt applications has started
  • 我怎样才能改变这种行为呢?这对我来说很重要,因为我希望在pyqt应用程序启动后动态地加载插件

1 个解决方案

#1


3  

This is not (yet) a real answer, but it might provide the first step in how to find one.

这还不是一个真正的答案,但它可能提供了找到答案的第一步。

Below is the minimal test case I suggested in my first comment on the question. It tests just one thing: does calling importlib.import_module after creating a QApplication make the interpreter hang on your system? Note that, for now, it only tries to import a module from the python standard library. It is vital to proceed one step at a time, and be careful to avoid introducing any potentially confounding variables.

下面是我在对这个问题的第一个评论中建议的最小测试用例。它只测试一件事:调用importlib。在创建QApplication之后让解释器挂在您的系统上吗?注意,目前它只尝试从python标准库中导入模块。一次只做一步是非常重要的,并且要小心避免引入任何潜在的混淆变量。

Please run this script exactly as described below, and add the output to your question. (Even if option 2 doesn't hang, the sys.path details are likely to be relevant).

请按照下面描述的那样运行此脚本,并将输出添加到您的问题中。(即使选项2没有挂起,系统。路径细节可能是相关的)。

import sys, importlib
from PyQt5 import QtWidgets

print('Sys Path:')
print('  %s\n' % '\n  '.join(sys.path))

mod = None
modname = 'collections.abc'
# modname = 'PyQt5.Qt'

if sys.argv[-1] == '1':
    print('Importing Before...\n')
    mod = importlib.import_module(modname)
    app = QtWidgets.QApplication(sys.argv)

elif sys.argv[-1] == '2':
    print('Importing After...\n')
    app = QtWidgets.QApplication(sys.argv)
    mod = importlib.import_module(modname)
    # from PyQt5 import Qt

print('Result: %r' % mod)

Run the script like this:

运行脚本如下:

$ python /tmp/test.py 1

then like this:

然后是这样的:

$ python /tmp/test.py 2

On my system (ArchLinux, Python-3.5.2, Qt-5.7.1, PyQt-5.7), the second one produces the following output:

在我的系统(ArchLinux, Python-3.5.2, Qt-5.7.1, PyQt-5.7)中,第二个输出如下:

Sys Path:
  /tmp
  /usr/lib/python35.zip
  /usr/lib/python3.5
  /usr/lib/python3.5/plat-linux
  /usr/lib/python3.5/lib-dynload
  /usr/lib/python3.5/site-packages

Importing After...

Result: <module 'collections.abc' from '/usr/lib/python3.5/collections/abc.py'>

UPDATE:

更新:

The first step established that importlib is not itself the cause of the problem. The second step is to identify which specific imported module is the source of the problem.

第一步确定importlib不是问题的根源。第二步是确定哪个特定的导入模块是问题的根源。

I have added two (commented) lines to the test script that will allow this to be done. The first checks whether importing PyQt5.Qt triggers a hang. If it does, the second checks whether a normal import statement will also trigger the hang.

我已经在测试脚本中添加了两个(注释)行,这将允许这样做。首先检查是否导入PyQt5。Qt触发挂起。如果它这样做了,第二个将检查一个普通的导入语句是否也会触发挂起。

Note that from PyQt5 import Qt effectively imports everything, including some very heavyweight and potentially troublesome modules like QtWebEngineWidgets. So it will be necessary to further refine the imports to properly identify the precise source of the problem.

注意,从PyQt5导入Qt可以有效地导入所有内容,包括一些非常重量级的、可能会带来麻烦的模块,如QtWebEngineWidgets。因此,有必要进一步细化进口,以正确确定问题的确切根源。

UPDATE 2:

更新2:

The QtWebEngineWidgets is a well-known source of problems, and often needs careful handling. The following interpreter session output seems relevant to your current problem:

QtWebEngineWidgets是众所周知的问题来源,通常需要小心处理。下面的解释器会话输出似乎与您当前的问题相关:

>>> from PyQt5 import QtWidgets, QtCore
>>> app = QtWidgets.QApplication([''])
>>> from PyQt5 import QtWebEngineWidgets
Qt WebEngine seems to be initialized from a plugin. Please set Qt::AA_ShareOpenGLContexts using QCoreApplication::setAttribute before constructing QGuiApplication.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: QtWebEngineWidgets must be imported before a QCoreApplication instance is created
>>>
>>> QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts)
>>> from PyQt5 import QtWebEngineWidgets
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: QtWebEngineWidgets must be imported before a QCoreApplication instance is created

This is all normal behaviour (although at the moment I can't find any official documentation for it). But let's try the same thing using the Qt module:

这都是正常的行为(尽管目前我找不到任何官方文件)。但是让我们用Qt模块尝试同样的事情:

>>> from PyQt5 import QtWidgets, QtCore
>>> QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts)
>>> app = QtWidgets.QApplication([''])
>>> from PyQt5 import Qt
>>> Qt.QWeb
Qt.QWebChannel(                      Qt.QWebEngineUrlRequestInterceptor(  Qt.QWebHitTestResult(                Qt.QWebSocketCorsAuthenticator(
Qt.QWebChannelAbstractTransport(     Qt.QWebEngineUrlRequestJob(          Qt.QWebInspector(                    Qt.QWebSocketProtocol(
Qt.QWebDatabase(                     Qt.QWebEngineUrlSchemeHandler(       Qt.QWebPage(                         Qt.QWebSocketServer(
Qt.QWebElement(                      Qt.QWebFrame(                        Qt.QWebPluginFactory(                Qt.QWebView(
Qt.QWebElementCollection(            Qt.QWebHistory(                      Qt.QWebSecurityOrigin(
Qt.QWebEngineCookieStore(            Qt.QWebHistoryInterface(             Qt.QWebSettings(
Qt.QWebEngineUrlRequestInfo(         Qt.QWebHistoryItem(                  Qt.QWebSocket(
>

So it looks like there's special handling for the Qt module when it's imported after a QApplication is created - although some QWebEngine classes are available, most of them have been omitted (e.g. QWebEngineView, QWebEnginePage, etc). But it seems that in your particular setup, this may not be working as it should. If so, you'd probably have to take this up with the author of PyQt, as it might require knowledge of the inner workings of the Qt module.

因此,在创建QApplication之后导入Qt模块时,似乎有一些特殊的处理——尽管一些QWebEngine类是可用的,但大多数类都被省略了(例如QWebEngineView、QWebEnginePage等)。但似乎在您的特定设置中,这可能不会正常工作。如果是这样,您可能需要与PyQt的作者讨论这个问题,因为它可能需要了解Qt模块的内部工作原理。

#1


3  

This is not (yet) a real answer, but it might provide the first step in how to find one.

这还不是一个真正的答案,但它可能提供了找到答案的第一步。

Below is the minimal test case I suggested in my first comment on the question. It tests just one thing: does calling importlib.import_module after creating a QApplication make the interpreter hang on your system? Note that, for now, it only tries to import a module from the python standard library. It is vital to proceed one step at a time, and be careful to avoid introducing any potentially confounding variables.

下面是我在对这个问题的第一个评论中建议的最小测试用例。它只测试一件事:调用importlib。在创建QApplication之后让解释器挂在您的系统上吗?注意,目前它只尝试从python标准库中导入模块。一次只做一步是非常重要的,并且要小心避免引入任何潜在的混淆变量。

Please run this script exactly as described below, and add the output to your question. (Even if option 2 doesn't hang, the sys.path details are likely to be relevant).

请按照下面描述的那样运行此脚本,并将输出添加到您的问题中。(即使选项2没有挂起,系统。路径细节可能是相关的)。

import sys, importlib
from PyQt5 import QtWidgets

print('Sys Path:')
print('  %s\n' % '\n  '.join(sys.path))

mod = None
modname = 'collections.abc'
# modname = 'PyQt5.Qt'

if sys.argv[-1] == '1':
    print('Importing Before...\n')
    mod = importlib.import_module(modname)
    app = QtWidgets.QApplication(sys.argv)

elif sys.argv[-1] == '2':
    print('Importing After...\n')
    app = QtWidgets.QApplication(sys.argv)
    mod = importlib.import_module(modname)
    # from PyQt5 import Qt

print('Result: %r' % mod)

Run the script like this:

运行脚本如下:

$ python /tmp/test.py 1

then like this:

然后是这样的:

$ python /tmp/test.py 2

On my system (ArchLinux, Python-3.5.2, Qt-5.7.1, PyQt-5.7), the second one produces the following output:

在我的系统(ArchLinux, Python-3.5.2, Qt-5.7.1, PyQt-5.7)中,第二个输出如下:

Sys Path:
  /tmp
  /usr/lib/python35.zip
  /usr/lib/python3.5
  /usr/lib/python3.5/plat-linux
  /usr/lib/python3.5/lib-dynload
  /usr/lib/python3.5/site-packages

Importing After...

Result: <module 'collections.abc' from '/usr/lib/python3.5/collections/abc.py'>

UPDATE:

更新:

The first step established that importlib is not itself the cause of the problem. The second step is to identify which specific imported module is the source of the problem.

第一步确定importlib不是问题的根源。第二步是确定哪个特定的导入模块是问题的根源。

I have added two (commented) lines to the test script that will allow this to be done. The first checks whether importing PyQt5.Qt triggers a hang. If it does, the second checks whether a normal import statement will also trigger the hang.

我已经在测试脚本中添加了两个(注释)行,这将允许这样做。首先检查是否导入PyQt5。Qt触发挂起。如果它这样做了,第二个将检查一个普通的导入语句是否也会触发挂起。

Note that from PyQt5 import Qt effectively imports everything, including some very heavyweight and potentially troublesome modules like QtWebEngineWidgets. So it will be necessary to further refine the imports to properly identify the precise source of the problem.

注意,从PyQt5导入Qt可以有效地导入所有内容,包括一些非常重量级的、可能会带来麻烦的模块,如QtWebEngineWidgets。因此,有必要进一步细化进口,以正确确定问题的确切根源。

UPDATE 2:

更新2:

The QtWebEngineWidgets is a well-known source of problems, and often needs careful handling. The following interpreter session output seems relevant to your current problem:

QtWebEngineWidgets是众所周知的问题来源,通常需要小心处理。下面的解释器会话输出似乎与您当前的问题相关:

>>> from PyQt5 import QtWidgets, QtCore
>>> app = QtWidgets.QApplication([''])
>>> from PyQt5 import QtWebEngineWidgets
Qt WebEngine seems to be initialized from a plugin. Please set Qt::AA_ShareOpenGLContexts using QCoreApplication::setAttribute before constructing QGuiApplication.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: QtWebEngineWidgets must be imported before a QCoreApplication instance is created
>>>
>>> QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts)
>>> from PyQt5 import QtWebEngineWidgets
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: QtWebEngineWidgets must be imported before a QCoreApplication instance is created

This is all normal behaviour (although at the moment I can't find any official documentation for it). But let's try the same thing using the Qt module:

这都是正常的行为(尽管目前我找不到任何官方文件)。但是让我们用Qt模块尝试同样的事情:

>>> from PyQt5 import QtWidgets, QtCore
>>> QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts)
>>> app = QtWidgets.QApplication([''])
>>> from PyQt5 import Qt
>>> Qt.QWeb
Qt.QWebChannel(                      Qt.QWebEngineUrlRequestInterceptor(  Qt.QWebHitTestResult(                Qt.QWebSocketCorsAuthenticator(
Qt.QWebChannelAbstractTransport(     Qt.QWebEngineUrlRequestJob(          Qt.QWebInspector(                    Qt.QWebSocketProtocol(
Qt.QWebDatabase(                     Qt.QWebEngineUrlSchemeHandler(       Qt.QWebPage(                         Qt.QWebSocketServer(
Qt.QWebElement(                      Qt.QWebFrame(                        Qt.QWebPluginFactory(                Qt.QWebView(
Qt.QWebElementCollection(            Qt.QWebHistory(                      Qt.QWebSecurityOrigin(
Qt.QWebEngineCookieStore(            Qt.QWebHistoryInterface(             Qt.QWebSettings(
Qt.QWebEngineUrlRequestInfo(         Qt.QWebHistoryItem(                  Qt.QWebSocket(
>

So it looks like there's special handling for the Qt module when it's imported after a QApplication is created - although some QWebEngine classes are available, most of them have been omitted (e.g. QWebEngineView, QWebEnginePage, etc). But it seems that in your particular setup, this may not be working as it should. If so, you'd probably have to take this up with the author of PyQt, as it might require knowledge of the inner workings of the Qt module.

因此,在创建QApplication之后导入Qt模块时,似乎有一些特殊的处理——尽管一些QWebEngine类是可用的,但大多数类都被省略了(例如QWebEngineView、QWebEnginePage等)。但似乎在您的特定设置中,这可能不会正常工作。如果是这样,您可能需要与PyQt的作者讨论这个问题,因为它可能需要了解Qt模块的内部工作原理。