2016-12-15 34 views
2

ОБЗОРмодули PyQt не могут быть импортированы после QtWidgets.QApplication (sys.argv)

У меня возникли проблемы импорта модулей после строки 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') 
  • Если я запустил python main.py 1, все работает должным образом.
  • Если я запустил python main.py 2, процесс зависает (возможно, в бесконечном цикле) без каких-либо ошибок.

Выход из python main.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) 

ПОПЫТКИ

Испытано с парой virtualenvs на win7:

  • Python 3.5.1 (v3.5.1:37a07cee5969, Dec 6 2015, 01:54:25) [MSC v.1900 64 bit (AMD64)] on win32 на win7
  • Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 25 2016, 22:01:18) [MSC v.1900 32 bit (Intel)] on win32

PyQt был установлен на virtualenvs с использованием пипа и версия эти из них:

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

Применимая ИНФОРМАЦИЯ

Некоторые очень хорошие люди из #pyqt freenode канала помогли мне проверить репо и ни один из них не смог воспроизвести проблему, версии и платформы python, которые они использовали:

  • win10 - 3.5.2 | Анаконда 4.1.1 (64-битный)
  • Win8 - 3.5.2 (v3.5.2: 4def2a2901a5, 25 июня 2016, 22:01:18)
  • убунту 16,04 - 3.5 0,2 (по умолчанию, 17 ноября 2016, 17:05:23)

ВОПРОСЫ

  • Что причина from PyQt5 import Qt (или других PyQT модулей) застрять на моей коробке и других не людей способность воспроизводить?
  • Как я могу исправить это поведение? Это важно для меня, потому что я хотел бы динамически загружать плагины после запуска моих приложений pyqt.
+0

Одно конкретное предложение: создать тестовый скрипт, который просто пытается выполнить 'importlib.import_module (mod_name)' до и после создания 'QApplication'.Если он все еще висит, у вас есть мекс; если он не зависает, вы наверняка знаете, что вы недостаточно отлаживали тестовое задание. Должна быть возможность реорганизовать 'list_plugins' в автономную функцию. Затем вы можете просто указать его в любом каталоге, содержащем файлы '* .py', и посмотреть, все ли он зависает. Идея состоит в том, чтобы изолировать только один небольшой раздел кода, который вызывает проблему и устраняет * все * еще. – ekhumoro

+0

Можете ли вы попробовать два предложения, которые я сделал в своих предыдущих комментариях? Это должно быть всего около десяти минут работы, и это позволит вам разместить надлежащую mcve. Другие вещи, вероятно, не имеют значения - это почти наверняка проблема, характерная для вашей конкретной установки. – ekhumoro

+0

@ekhumoro Хорошо, я обновил репо еще раз. Если у вас есть время, сообщите мне, если вы увидите что-то еще, что может быть улучшено дальше, чтобы еще больше уменьшить сложность. – BPL

ответ

1

Это еще не настоящий ответ, но это может стать первым шагом в том, как его найти.

Ниже приведен минимальный тестовый пример, который я предложил в своем первом комментарии к вопросу. Он тестирует только один вещь: звонит ли importlib.import_module после создания QApplication заставляет интерпретатор зависать в вашей системе?Обратите внимание, что на данный момент он пытается импортировать только модуль из стандартной библиотеки python. Крайне важно продолжать шаг за шагом и быть осторожным, чтобы не вводить какие-либо потенциально смешающие переменные.

Пожалуйста, запустите этот скрипт , как описано ниже, и добавьте вывод к вашему вопросу. (Даже если опция 2 не зависает, возможно, будут актуальны данные sys.path).

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) 

Запустить скрипт так:

$ python /tmp/test.py 1 

тогда как это:

$ python /tmp/test.py 2 

В моей системе (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'> 

ОБНОВЛЕНИЕ:

На первом этапе установлено, что importlib сам по себе не является причиной проблемы. Второй шаг - определить, какой конкретный импортированный модуль является источником проблемы.

Я добавил две (прокомментированные) строки в тестовый скрипт, который позволит это сделать. Первый проверяет, запускает ли импорт PyQt5.Qt. Если это произойдет, вторая проверяет, может ли нормальный оператор import инициировать зависание.

Обратите внимание, что from PyQt5 import Qt эффективно импортирует все, в том числе некоторые очень тяжеловесных и потенциально проблемных модулей, таких как QtWebEngineWidgets. Поэтому необходимо будет дополнительно уточнить импорт для правильной идентификации точного источника проблемы.

UPDATE 2:

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 

Это все нормальное поведение (хотя в данный момент я не могу найти какую-либо официальную документацию на него). Но давайте попробуем то же самое с помощью 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(
> 

Так что, похоже, есть специальная обработка для Qt модуля, когда он импортируется послеQApplication создан - хотя некоторыхQWebEngine классов доступны, наиболее из них опущены (например, QWebEngineView, QWebEnginePage и т. д.). Но кажется, что в вашей конкретной установке это может не работать так, как должно. Если это так, вам, вероятно, придется взять это с автором PyQt, так как это может потребовать знания внутренней работы модуля Qt.

+0

Прежде всего, спасибо за первую попытку помочь, надеюсь, это вдохновит других внести свой вклад в некоторые новые идеи. Я должен сказать, что это хорошая идея, вы объединили {main_ok.py, main_bug.py} в test.py, позже я обновлю репо и вопрос, чтобы упростить это. К сожалению, ваш тест не обнаружит никаких проблем (без зависания) на моей коробке. Одна вещь, которую вы увидите в последнем фиксации моего репо, - это файл 'gui \ operator_object.py', содержащий' from PyQt5 import Qt' ... но до того, как я получил 'от импорта PyQt5.Qt qDrawShadeRect', я понял оба они производят повесить здесь на моем ящике. – BPL

+0

Кроме того, одна важная деталь, если я заменил 'from PyQt5 import Qt' в' gui \ operator_object.py' на 'import collections.abc', я не буду испытывать зависание. Кажется, по некоторым причинам, модули PyQt - это те, кто позволяет мне воспроизвести здесь ошибку. +1 за ваше время и помощь btw; D – BPL

+0

@BPL. Итак, теперь я показал вам, как правильно тестировать, вы должны быть в состоянии сделать все остальное самостоятельно. Если вы выполните небольшие шаги, тщательно проверив каждый элемент отдельно, вы, в конечном счете, найдете реальный источник проблемы. Было бы полезно, если бы вы изменили название и большую часть содержимого вашего вопроса, так как теперь я убедился, что проблема 'import_module' не сама по себе * вызывает проблему. – ekhumoro