Merge pull request #272 from pypeclub/bugfix/264-Pyblish-pype_is_too_slow_with_10_instances

Bugfix/264 pyblish pype is too slow with 10 instances
This commit is contained in:
Milan Kolar 2020-06-18 13:11:48 +02:00 committed by GitHub
commit 29a14a46fd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 174 additions and 84 deletions

View file

@ -491,3 +491,24 @@ QToolButton {
#TerminalFilerBtn[type="log_critical"]:checked {color: rgb(255, 79, 117);}
#TerminalFilerBtn[type="log_critical"] {color: rgba(255, 79, 117, 63);}
#SuspendLogsBtn {
background: #444;
border: none;
border-top-right-radius: 7px;
border-bottom-right-radius: 7px;
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
font-family: "FontAwesome";
font-size: 11pt;
color: white;
padding: 0px;
}
#SuspendLogsBtn:hover {
background: #333;
}
#SuspendLogsBtn:disabled {
background: #4c4c4c;
}

View file

@ -86,7 +86,6 @@ class Controller(QtCore.QObject):
# - passing collectors order disables plugin/instance toggle
self.collectors_order = None
self.collect_state = 0
self.collected = False
# - passing validators order disables validate button and gives ability
# to know when to stop on validate button press

View file

@ -32,7 +32,6 @@ from .awesome import tags as awesome
import Qt
from Qt import QtCore, QtGui
from six import text_type
from six.moves import queue
from .vendor import qtawesome
from .constants import PluginStates, InstanceStates, GroupStates, Roles
@ -49,6 +48,7 @@ TerminalDetailType = QtGui.QStandardItem.UserType + 4
class QAwesomeTextIconFactory:
icons = {}
@classmethod
def icon(cls, icon_name):
if icon_name not in cls.icons:
@ -58,6 +58,7 @@ class QAwesomeTextIconFactory:
class QAwesomeIconFactory:
icons = {}
@classmethod
def icon(cls, icon_name, icon_color):
if icon_name not in cls.icons:
@ -1009,7 +1010,7 @@ class ArtistProxy(QtCore.QAbstractProxyModel):
return QtCore.QModelIndex()
class TerminalModel(QtGui.QStandardItemModel):
class TerminalDetailItem(QtGui.QStandardItem):
key_label_record_map = (
("instance", "Instance"),
("msg", "Message"),
@ -1022,6 +1023,57 @@ class TerminalModel(QtGui.QStandardItemModel):
("msecs", "Millis")
)
def __init__(self, record_item):
self.record_item = record_item
self.msg = None
msg = record_item.get("msg")
if msg is None:
msg = record_item["label"].split("\n")[0]
super(TerminalDetailItem, self).__init__(msg)
def data(self, role=QtCore.Qt.DisplayRole):
if role in (QtCore.Qt.DisplayRole, QtCore.Qt.EditRole):
if self.msg is None:
self.msg = self.compute_detail_text(self.record_item)
return self.msg
return super(TerminalDetailItem, self).data(role)
def compute_detail_text(self, item_data):
if item_data["type"] == "info":
return item_data["label"]
html_text = ""
for key, title in self.key_label_record_map:
if key not in item_data:
continue
value = item_data[key]
text = (
str(value)
.replace("<", "&#60;")
.replace(">", "&#62;")
.replace('\n', '<br/>')
.replace(' ', '&nbsp;')
)
title_tag = (
'<span style=\" font-size:8pt; font-weight:600;'
# ' background-color:#bbb; color:#333;\" >{}:</span> '
' color:#fff;\" >{}:</span> '
).format(title)
html_text += (
'<tr><td width="100%" align=left>{}</td></tr>'
'<tr><td width="100%">{}</td></tr>'
).format(title_tag, text)
html_text = '<table width="100%" cellspacing="3">{}</table>'.format(
html_text
)
return html_text
class TerminalModel(QtGui.QStandardItemModel):
item_icon_name = {
"info": "fa.info",
"record": "fa.circle",
@ -1053,38 +1105,38 @@ class TerminalModel(QtGui.QStandardItemModel):
self.reset()
def reset(self):
self.items_to_set_widget = queue.Queue()
self.clear()
def prepare_records(self, result):
def prepare_records(self, result, suspend_logs):
prepared_records = []
instance_name = None
instance = result["instance"]
if instance is not None:
instance_name = instance.data["name"]
for record in result.get("records") or []:
if isinstance(record, dict):
record_item = record
else:
record_item = {
"label": text_type(record.msg),
"type": "record",
"levelno": record.levelno,
"threadName": record.threadName,
"name": record.name,
"filename": record.filename,
"pathname": record.pathname,
"lineno": record.lineno,
"msg": text_type(record.msg),
"msecs": record.msecs,
"levelname": record.levelname
}
if not suspend_logs:
for record in result.get("records") or []:
if isinstance(record, dict):
record_item = record
else:
record_item = {
"label": text_type(record.msg),
"type": "record",
"levelno": record.levelno,
"threadName": record.threadName,
"name": record.name,
"filename": record.filename,
"pathname": record.pathname,
"lineno": record.lineno,
"msg": text_type(record.msg),
"msecs": record.msecs,
"levelname": record.levelname
}
if instance_name is not None:
record_item["instance"] = instance_name
if instance_name is not None:
record_item["instance"] = instance_name
prepared_records.append(record_item)
prepared_records.append(record_item)
error = result.get("error")
if error:
@ -1140,49 +1192,14 @@ class TerminalModel(QtGui.QStandardItemModel):
self.appendRow(top_item)
detail_text = self.prepare_detail_text(record_item)
detail_item = QtGui.QStandardItem(detail_text)
detail_item = TerminalDetailItem(record_item)
detail_item.setData(TerminalDetailType, Roles.TypeRole)
top_item.appendRow(detail_item)
self.items_to_set_widget.put(detail_item)
def update_with_result(self, result):
for record in result["records"]:
self.append(record)
def prepare_detail_text(self, item_data):
if item_data["type"] == "info":
return item_data["label"]
html_text = ""
for key, title in self.key_label_record_map:
if key not in item_data:
continue
value = item_data[key]
text = (
str(value)
.replace("<", "&#60;")
.replace(">", "&#62;")
.replace('\n', '<br/>')
.replace(' ', '&nbsp;')
)
title_tag = (
'<span style=\" font-size:8pt; font-weight:600;'
# ' background-color:#bbb; color:#333;\" >{}:</span> '
' color:#fff;\" >{}:</span> '
).format(title)
html_text += (
'<tr><td width="100%" align=left>{}</td></tr>'
'<tr><td width="100%">{}</td></tr>'
).format(title_tag, text)
html_text = '<table width="100%" cellspacing="3">{}</table>'.format(
html_text
)
return html_text
class TerminalProxy(QtCore.QSortFilterProxyModel):
filter_buttons_checks = {

View file

@ -1,5 +1,6 @@
from Qt import QtCore, QtWidgets
from . import model
from . import widgets
from .constants import Roles
@ -190,6 +191,23 @@ class TerminalView(QtWidgets.QTreeView):
self.updateGeometry()
self.scrollToBottom()
def expand(self, index):
"""Wrapper to set widget for expanded index."""
model = index.model()
row_count = model.rowCount(index)
is_new = False
for child_idx in range(row_count):
child_index = model.index(child_idx, index.column(), index)
widget = self.indexWidget(child_index)
if widget is None:
is_new = True
msg = child_index.data(QtCore.Qt.DisplayRole)
widget = widgets.TerminalDetail(msg)
self.setIndexWidget(child_index, widget)
super(TerminalView, self).expand(index)
if is_new:
self.updateGeometries()
def resizeEvent(self, event):
super(self.__class__, self).resizeEvent(event)
self.model().layoutChanged.emit()

View file

@ -321,11 +321,6 @@ class PerspectiveWidget(QtWidgets.QWidget):
data = {"records": records}
self.terminal_model.reset()
self.terminal_model.update_with_result(data)
while not self.terminal_model.items_to_set_widget.empty():
item = self.terminal_model.items_to_set_widget.get()
widget = TerminalDetail(item.data(QtCore.Qt.DisplayRole))
index = self.terminal_proxy.mapFromSource(item.index())
self.terminal_view.setIndexWidget(index, widget)
self.records.button_toggle_text.setText(
"{} ({})".format(self.l_rec, len_records)

View file

@ -54,6 +54,7 @@ class Window(QtWidgets.QDialog):
def __init__(self, controller, parent=None):
super(Window, self).__init__(parent=parent)
self._suspend_logs = False
# Use plastique style for specific ocations
# TODO set style name via environment variable
low_keys = {
@ -95,6 +96,18 @@ class Window(QtWidgets.QDialog):
header_tab_terminal = QtWidgets.QRadioButton(header_tab_widget)
header_spacer = QtWidgets.QWidget(header_tab_widget)
button_suspend_logs_widget = QtWidgets.QWidget()
button_suspend_logs_widget_layout = QtWidgets.QHBoxLayout(
button_suspend_logs_widget
)
button_suspend_logs_widget_layout.setContentsMargins(0, 10, 0, 10)
button_suspend_logs = QtWidgets.QPushButton(header_widget)
button_suspend_logs.setFixedWidth(7)
button_suspend_logs.setSizePolicy(
QtWidgets.QSizePolicy.Preferred,
QtWidgets.QSizePolicy.Expanding
)
button_suspend_logs_widget_layout.addWidget(button_suspend_logs)
header_aditional_btns = QtWidgets.QWidget(header_tab_widget)
aditional_btns_layout = QtWidgets.QHBoxLayout(header_aditional_btns)
@ -109,9 +122,11 @@ class Window(QtWidgets.QDialog):
layout_tab.addWidget(header_tab_artist, 0)
layout_tab.addWidget(header_tab_overview, 0)
layout_tab.addWidget(header_tab_terminal, 0)
layout_tab.addWidget(button_suspend_logs_widget, 0)
# Compress items to the left
layout_tab.addWidget(header_spacer, 1)
layout_tab.addWidget(header_aditional_btns, 1)
layout_tab.addWidget(header_aditional_btns, 0)
layout = QtWidgets.QHBoxLayout(header_widget)
layout.setContentsMargins(0, 0, 0, 0)
@ -226,6 +241,10 @@ class Window(QtWidgets.QDialog):
footer_info = QtWidgets.QLabel(footer_widget)
footer_spacer = QtWidgets.QWidget(footer_widget)
footer_button_stop = QtWidgets.QPushButton(
awesome["stop"], footer_widget
)
footer_button_reset = QtWidgets.QPushButton(
awesome["refresh"], footer_widget
)
@ -235,14 +254,12 @@ class Window(QtWidgets.QDialog):
footer_button_play = QtWidgets.QPushButton(
awesome["play"], footer_widget
)
footer_button_stop = QtWidgets.QPushButton(
awesome["stop"], footer_widget
)
layout = QtWidgets.QHBoxLayout()
layout.setContentsMargins(5, 5, 5, 5)
layout.addWidget(footer_info, 0)
layout.addWidget(footer_spacer, 1)
layout.addWidget(footer_button_stop, 0)
layout.addWidget(footer_button_reset, 0)
layout.addWidget(footer_button_validate, 0)
@ -342,10 +359,11 @@ class Window(QtWidgets.QDialog):
"TerminalView": terminal_view,
# Buttons
"Play": footer_button_play,
"Validate": footer_button_validate,
"Reset": footer_button_reset,
"SuspendLogsBtn": button_suspend_logs,
"Stop": footer_button_stop,
"Reset": footer_button_reset,
"Validate": footer_button_validate,
"Play": footer_button_play,
# Misc
"HeaderSpacer": header_spacer,
@ -370,10 +388,11 @@ class Window(QtWidgets.QDialog):
overview_page,
terminal_page,
footer_widget,
footer_button_play,
footer_button_validate,
button_suspend_logs,
footer_button_stop,
footer_button_reset,
footer_button_validate,
footer_button_play,
footer_spacer,
closing_placeholder
):
@ -419,6 +438,7 @@ class Window(QtWidgets.QDialog):
overview_instance_view.toggled.connect(self.on_instance_toggle)
overview_plugin_view.toggled.connect(self.on_plugin_toggle)
button_suspend_logs.clicked.connect(self.on_suspend_clicked)
footer_button_stop.clicked.connect(self.on_stop_clicked)
footer_button_reset.clicked.connect(self.on_reset_clicked)
footer_button_validate.clicked.connect(self.on_validate_clicked)
@ -442,10 +462,11 @@ class Window(QtWidgets.QDialog):
self.terminal_filters_widget = terminal_filters_widget
self.footer_widget = footer_widget
self.button_suspend_logs = button_suspend_logs
self.footer_button_stop = footer_button_stop
self.footer_button_reset = footer_button_reset
self.footer_button_validate = footer_button_validate
self.footer_button_play = footer_button_play
self.footer_button_stop = footer_button_stop
self.overview_instance_view = overview_instance_view
self.overview_plugin_view = overview_plugin_view
@ -612,6 +633,13 @@ class Window(QtWidgets.QDialog):
self.footer_button_play.setEnabled(False)
self.footer_button_stop.setEnabled(False)
def on_suspend_clicked(self):
self._suspend_logs = not self._suspend_logs
if self.state["current_page"] == "terminal":
self.on_tab_changed("overview")
self.tabs["terminal"].setVisible(not self._suspend_logs)
def on_comment_entered(self):
"""The user has typed a comment."""
self.controller.context.data["comment"] = self.comment_box.text()
@ -726,6 +754,8 @@ class Window(QtWidgets.QDialog):
self.on_tab_changed(self.state["current_page"])
self.update_compatibility()
self.button_suspend_logs.setEnabled(False)
self.footer_button_validate.setEnabled(True)
self.footer_button_reset.setEnabled(True)
self.footer_button_stop.setEnabled(False)
@ -775,6 +805,12 @@ class Window(QtWidgets.QDialog):
self.footer_widget.setProperty("success", 0)
self.footer_widget.style().polish(self.footer_widget)
suspend_log_bool = (
self.controller.collect_state == 1
and not self.controller.stopped
)
self.button_suspend_logs.setEnabled(suspend_log_bool)
def on_was_skipped(self, plugin):
plugin_item = self.plugin_model.plugin_items[plugin.id]
plugin_item.setData(
@ -834,17 +870,15 @@ class Window(QtWidgets.QDialog):
if self.tabs["artist"].isChecked():
self.tabs["overview"].toggle()
result["records"] = self.terminal_model.prepare_records(result)
result["records"] = self.terminal_model.prepare_records(
result,
self._suspend_logs
)
plugin_item = self.plugin_model.update_with_result(result)
instance_item = self.instance_model.update_with_result(result)
self.terminal_model.update_with_result(result)
while not self.terminal_model.items_to_set_widget.empty():
item = self.terminal_model.items_to_set_widget.get()
widget = widgets.TerminalDetail(item.data(QtCore.Qt.DisplayRole))
index = self.terminal_proxy.mapFromSource(item.index())
self.terminal_view.setIndexWidget(index, widget)
self.update_compatibility()
@ -897,16 +931,19 @@ class Window(QtWidgets.QDialog):
self.footer_button_validate.setEnabled(False)
self.footer_button_play.setEnabled(False)
self.button_suspend_logs.setEnabled(False)
util.defer(5, self.controller.validate)
def publish(self):
self.info(self.tr("Preparing publish.."))
self.footer_button_stop.setEnabled(True)
self.footer_button_reset.setEnabled(False)
self.footer_button_validate.setEnabled(False)
self.footer_button_play.setEnabled(False)
self.button_suspend_logs.setEnabled(False)
util.defer(5, self.controller.publish)
def act(self, plugin_item, action):
@ -938,7 +975,10 @@ class Window(QtWidgets.QDialog):
plugin_item = self.plugin_model.plugin_items[result["plugin"].id]
action_state = plugin_item.data(Roles.PluginActionProgressRole)
action_state |= PluginActionStates.HasFinished
result["records"] = self.terminal_model.prepare_records(result)
result["records"] = self.terminal_model.prepare_records(
result,
self._suspend_logs
)
error = result.get("error")
if error: