Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Delivery in LibraryLoader - fixed sequence issue #1590

Merged
merged 1 commit into from
May 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 30 additions & 40 deletions pype/lib/delivery.py
Original file line number Diff line number Diff line change
Expand Up @@ -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']:
Expand Down Expand Up @@ -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": '<p>{}</p>'.format("<br>".join(__items))
})

if not items:
return {
"success": True,
"message": "Delivery Finished"
}

return {
"items": items,
"title": title,
"success": False,
"message": "Delivery Finished"
}
100 changes: 53 additions & 47 deletions pype/plugins/global/load/delivery.py
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -15,7 +16,7 @@
check_destination_path,
process_single_file,
process_sequence,
report
collect_frames
)


Expand Down Expand Up @@ -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)
Expand All @@ -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)

Expand All @@ -98,19 +92,23 @@ 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)
repre_checkboxes_layout.addRow(repre, checkbox)

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)
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -187,7 +186,7 @@ def deliver(self):
args = [
repre_path,
repre,
anatomy,
self.anatomy,
template_name,
anatomy_data,
format_dict,
Expand All @@ -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)
Expand All @@ -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

Expand Down Expand Up @@ -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."""
Expand All @@ -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 = "<h2>{}</h2>".format(result["message"])
msg = "Delivery finished"
if not report_items:
msg += " successfully"
else:
msg += " with errors"
txt = "<h2>{}</h2>".format(msg)
for header, data in report_items.items():
txt += "<h3>{}</h3>".format(header)
for item in data:
Expand Down