【发布时间】:2019-07-17 18:03:01
【问题描述】:
上下文:
我有一个 Flask 应用程序为资源 POST /start 提供服务。要执行的逻辑涉及到 PyQt5 QWebEnginePage 加载 URL 并返回有关它的某些数据。
问题:
当 QApplication 被执行(调用app.exec_())时,我收到警告:
WARNING: QApplication was not created in the main() thread.
然后是错误:
2019-07-17 13:06:19.461 Python[56513:5183122] *** Assertion failure in +[NSUndoManager _endTopLevelGroupings], /BuildRoot/Library/Caches/com.apple.xbs/Sources/Foundation/Foundation-1562/Foundation/Misc.subproj/NSUndoManager.m:361
2019-07-17 13:06:19.464 Python[56513:5183122] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+[NSUndoManager(NSInternal) _endTopLevelGroupings] is only safe to invoke on the main thread.'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff4e1abded __exceptionPreprocess + 256
1 libobjc.A.dylib 0x00007fff7a273720 objc_exception_throw + 48
...
...
122 libsystem_pthread.dylib 0x00007fff7b53826f _pthread_start + 70
123 libsystem_pthread.dylib 0x00007fff7b534415 thread_start + 13
)
libc++abi.dylib: terminating with uncaught exception of type NSException
Received signal 6
[0x00010a766de6]
[0x7fff7b52cb3d]
...
...
[0x000105a0de27]
[end of stack trace]
似乎 QApplication 总是需要在主线程上运行,但事实并非如此,因为 flask 在后台线程上运行资源。 我考虑过的一个可能的解决方案是将 QApplication 作为 os 子进程运行,但并不理想。
问题:
是否可以将其保留在 Flask 应用程序中?
示例 PyQt 类:
import sys
from PyQt5.QtWebEngineWidgets import QWebEnginePage
from PyQt5.QtWebEngineWidgets import QWebEngineProfile
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QUrl
class PyQtWebClient(QWebEnginePage):
def __init__(self, url):
# Pointless variable for showcase purposes
self.total_runtime = None
self.app = QApplication(sys.argv)
self.profile = QWebEngineProfile()
# This is a sample to show the constructor I am actually using, my 'profile' is more complex than this
super().__init__(self.profile, None)
# Register callback to run when the page loads
self.loadFinished.connect(self._on_load_finished)
self.load(QUrl(url))
self.app.exec_()
def _on_load_finished(self):
self.total_runtime = 10
if __name__ == '__main__':
url = "https://www.example.com"
page = PyQtWebClient(url)
Flask app.py 示例
from flask import Flask
from flask_restful import Resource, Api
from lenomi import PyQtWebClient
app = Flask(__name__)
api = Api(app)
class TestPyqt5(Resource):
def post(self):
web = PyQtWebClient("http://www.example.com")
# At this point PyQtWebClient should have finished loading the url, and the process is done
print(web.total_runtime)
api.add_resource(TestPyqt5, "/pyqt")
if __name__ == '__main__':
app.run(debug=True)
【问题讨论】:
-
什么是
total_runtime? -
我使用
total_runtime暗示此时PyQtWebClient应该已经完成加载。更新了代码。
标签: python flask pyqt5 flask-restful qapplication