From 57750495efd87a23d6ceeaf215b8fe20a4c2589d Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 25 May 2021 18:17:40 +0200 Subject: [PATCH] Delivery in LibraryLoader - fixed sequence issue Only single file was being created and overwritten --- pype/lib/delivery.py | 70 ++++++++----------- pype/plugins/global/load/delivery.py | 100 ++++++++++++++------------- 2 files changed, 83 insertions(+), 87 deletions(-) diff --git a/pype/lib/delivery.py b/pype/lib/delivery.py index a9561db5727..d7f32a4a002 100644 --- a/pype/lib/delivery.py +++ b/pype/lib/delivery.py @@ -7,6 +7,36 @@ import collections +def collect_frames(files): + """ + Returns dict of source path and its frame, if from sequence + + Uses clique as most precise solution + + Args: + files(list): list of source paths + Returns: + (dict): {'/asset/subset_v001.0001.png': '0001', ....} + """ + collections, remainder = clique.assemble(files) + + sources_and_frames = {} + if collections: + for collection in collections: + src_head = collection.head + src_tail = collection.tail + + for index in collection.indexes: + src_frame = collection.format("{padding}") % index + src_file_name = "{}{}{}".format(src_head, src_frame, + src_tail) + sources_and_frames[src_file_name] = src_frame + else: + sources_and_frames[remainder.pop()] = None + + return sources_and_frames + + def sizeof_fmt(num, suffix='B'): """Returns formatted string with size in appropriate unit""" for unit in ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi']: @@ -270,43 +300,3 @@ def process_sequence( uploaded += 1 return report_items, uploaded - - -def report(report_items): - """Returns dict with final status of delivery (succes, fail etc.).""" - items = [] - title = "Delivery report" - for msg, _items in report_items.items(): - if not _items: - continue - - if items: - items.append({"type": "label", "value": "---"}) - - items.append({ - "type": "label", - "value": "# {}".format(msg) - }) - if not isinstance(_items, (list, tuple)): - _items = [_items] - __items = [] - for item in _items: - __items.append(str(item)) - - items.append({ - "type": "label", - "value": '

{}

'.format("
".join(__items)) - }) - - if not items: - return { - "success": True, - "message": "Delivery Finished" - } - - return { - "items": items, - "title": title, - "success": False, - "message": "Delivery Finished" - } diff --git a/pype/plugins/global/load/delivery.py b/pype/plugins/global/load/delivery.py index 2b20d0daf8d..e474fe69c9c 100644 --- a/pype/plugins/global/load/delivery.py +++ b/pype/plugins/global/load/delivery.py @@ -1,10 +1,11 @@ -import collections -import os +from collections import defaultdict import copy +from Qt import QtWidgets, QtCore, QtGui + from avalon import api, style -from avalon.vendor.Qt import QtWidgets, QtCore, QtGui from avalon.api import AvalonMongoDB + from pype.api import Anatomy, config from pype import resources @@ -15,7 +16,7 @@ check_destination_path, process_single_file, process_sequence, - report + collect_frames ) @@ -53,19 +54,18 @@ def load(self, contexts, name=None, namespace=None, options=None): class DeliveryOptionsDialog(QtWidgets.QDialog): """Dialog to select template where to deliver selected representations.""" - SIZE_W = 950 - SIZE_H = 350 def __init__(self, contexts, log=None, parent=None): super(DeliveryOptionsDialog, self).__init__(parent=parent) - self.project = contexts[0]["project"]["name"] + project = contexts[0]["project"]["name"] + self.anatomy = Anatomy(project) self._representations = None self.log = log self.currently_uploaded = 0 self.dbcon = AvalonMongoDB() - self.dbcon.Session["AVALON_PROJECT"] = self.project + self.dbcon.Session["AVALON_PROJECT"] = project self.dbcon.install() self._set_representations(contexts) @@ -79,15 +79,9 @@ def __init__(self, contexts, log=None, parent=None): QtCore.Qt.WindowMinimizeButtonHint ) self.setStyleSheet(style.load_stylesheet()) - self.setMinimumSize(QtCore.QSize(self.SIZE_W, self.SIZE_H)) - - layout = QtWidgets.QVBoxLayout() - - input_layout = QtWidgets.QFormLayout() - input_layout.setContentsMargins(10, 15, 5, 5) dropdown = QtWidgets.QComboBox() - self.templates = self._get_templates(self.project) + self.templates = self._get_templates(self.anatomy) for name, _ in self.templates.items(): dropdown.addItem(name) @@ -98,12 +92,12 @@ def __init__(self, contexts, log=None, parent=None): root_line_edit = QtWidgets.QLineEdit() repre_checkboxes_layout = QtWidgets.QFormLayout() - repre_checkboxes_layout.setContentsMargins(10, 5, 5, 20) + repre_checkboxes_layout.setContentsMargins(10, 5, 5, 10) self._representation_checkboxes = {} for repre in self._get_representation_names(): checkbox = QtWidgets.QCheckBox() - checkbox.setChecked(True) + checkbox.setChecked(False) self._representation_checkboxes[repre] = checkbox checkbox.stateChanged.connect(self._update_selected_label) @@ -111,6 +105,10 @@ def __init__(self, contexts, log=None, parent=None): selected_label = QtWidgets.QLabel() + input_widget = QtWidgets.QWidget(self) + input_layout = QtWidgets.QFormLayout(input_widget) + input_layout.setContentsMargins(10, 15, 5, 5) + input_layout.addRow("Selected representations", selected_label) input_layout.addRow("Delivery template", dropdown) input_layout.addRow("Template value", template_label) @@ -123,20 +121,21 @@ def __init__(self, contexts, log=None, parent=None): progress_bar = QtWidgets.QProgressBar(self) progress_bar.setMinimum = 0 progress_bar.setMaximum = 100 - progress_bar.hide() + progress_bar.setVisible(False) text_area = QtWidgets.QTextEdit() text_area.setReadOnly(True) - text_area.hide() + text_area.setVisible(False) text_area.setMinimumHeight(100) - layout.addLayout(input_layout) + layout = QtWidgets.QVBoxLayout(self) + + layout.addWidget(input_widget) + layout.addStretch(1) layout.addWidget(btn_delivery) layout.addWidget(progress_bar) layout.addWidget(text_area) - self.setLayout(layout) - self.selected_label = selected_label self.template_label = template_label self.dropdown = dropdown @@ -156,26 +155,26 @@ def __init__(self, contexts, log=None, parent=None): def deliver(self): """Main method to loop through all selected representations""" - self.progress_bar.show() + self.progress_bar.setVisible(True) self.btn_delivery.setEnabled(False) - # self.resize(self.width(), self.height() + 50) + QtWidgets.QApplication.processEvents() - report_items = collections.defaultdict(list) + report_items = defaultdict(list) selected_repres = self._get_selected_repres() - anatomy = Anatomy(self.project) + datetime_data = config.get_datetime_data() template_name = self.dropdown.currentText() - format_dict = get_format_dict(anatomy, self.root_line_edit.text()) + format_dict = get_format_dict(self.anatomy, self.root_line_edit.text()) for repre in self._representations: if repre["name"] not in selected_repres: continue - repre_path = path_from_represenation(repre, anatomy) + repre_path = path_from_represenation(repre, self.anatomy) anatomy_data = copy.deepcopy(repre["context"]) new_report_items = check_destination_path(str(repre["_id"]), - anatomy, + self.anatomy, anatomy_data, datetime_data, template_name) @@ -187,7 +186,7 @@ def deliver(self): args = [ repre_path, repre, - anatomy, + self.anatomy, template_name, anatomy_data, format_dict, @@ -196,9 +195,16 @@ def deliver(self): ] if repre.get("files"): + src_paths = [] for repre_file in repre["files"]: - src_path = anatomy.fill_root(repre_file["path"]) + src_path = self.anatomy.fill_root(repre_file["path"]) + src_paths.append(src_path) + sources_and_frames = collect_frames(src_paths) + + for src_path, frame in sources_and_frames.items(): args[0] = src_path + if frame: + anatomy_data["frame"] = frame new_report_items, uploaded = process_single_file(*args) report_items.update(new_report_items) self._update_progress(uploaded) @@ -214,26 +220,21 @@ def deliver(self): report_items.update(new_report_items) self._update_progress(uploaded) - self.text_area.setText(self._format_report(report(report_items), - report_items)) - self.text_area.show() - - self.resize(self.width(), self.height() + 125) + self.text_area.setText(self._format_report(report_items)) + self.text_area.setVisible(True) def _get_representation_names(self): """Get set of representation names for checkbox filtering.""" return set([repre["name"] for repre in self._representations]) - def _get_templates(self, project_name): + def _get_templates(self, anatomy): """Adds list of delivery templates from Anatomy to dropdown.""" - anatomy = Anatomy(project_name) - templates = {} - for key, template in ( - anatomy.templates.get("delivery") or {}).items(): - # Use only keys with `{root}` or `{root[*]}` in value - if isinstance(template, str) and "{root" in template: - templates[key] = template + for template_name, value in anatomy.templates["delivery"].items(): + if not isinstance(value, str) or not value.startswith('{root'): + continue + + templates[template_name] = value return templates @@ -292,7 +293,7 @@ def _update_template_value(self, _index=None): template_value = self.templates.get(name) if template_value: self.btn_delivery.setEnabled(True) - self.template_label.setText(str(template_value)) + self.template_label.setText(template_value) def _update_progress(self, uploaded): """Update progress bar after each repre copied.""" @@ -301,9 +302,14 @@ def _update_progress(self, uploaded): ratio = self.currently_uploaded / self.files_selected self.progress_bar.setValue(ratio * self.progress_bar.maximum()) - def _format_report(self, result, report_items): + def _format_report(self, report_items): """Format final result and error details as html.""" - txt = "

{}

".format(result["message"]) + msg = "Delivery finished" + if not report_items: + msg += " successfully" + else: + msg += " with errors" + txt = "

{}

".format(msg) for header, data in report_items.items(): txt += "

{}

".format(header) for item in data: