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

TrayPublisher: Simple creation enhancements and fixes #3513

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
be4ac5b
add multiple items and review boolean to tray creator settings
mkolar Jul 13, 2022
654b0fb
delete obsolete create_review_family plugin
mkolar Jul 13, 2022
a427648
implemented internal drag and drop and disabled sorting
iLLiCiTiT Jul 13, 2022
2fbc1aa
make drop available
iLLiCiTiT Jul 13, 2022
08a9613
fix label height in files widget
iLLiCiTiT Jul 13, 2022
31bd3a8
Merge branch 'develop' into feature/OP-3578_traypublisher_file_defini…
iLLiCiTiT Jul 14, 2022
84068bd
added ability to zoom text in report
iLLiCiTiT Jul 14, 2022
fa2b480
Merge branch 'develop' into feature/OP-3578_traypublisher_file_defini…
iLLiCiTiT Jul 14, 2022
c16a2d6
moved collect cleanup keys earlier
iLLiCiTiT Jul 14, 2022
43d744b
instance data is filled with instance asset specific values if are no…
iLLiCiTiT Jul 14, 2022
4f133d2
changed allow_review to reviewable which affect default value of revi…
iLLiCiTiT Jul 14, 2022
1eceb72
define some extensions for which reviewable could work
iLLiCiTiT Jul 14, 2022
a2a8362
instance staging dir lead to temp
iLLiCiTiT Jul 14, 2022
a088db2
modified validator if not existing paths as there is a chance that fi…
iLLiCiTiT Jul 14, 2022
bc09a92
modified simple instance collector to be able handle multivalue of fi…
iLLiCiTiT Jul 14, 2022
b51c44d
modified error message
iLLiCiTiT Jul 14, 2022
465c506
fix typo
iLLiCiTiT Jul 14, 2022
9c1dd8b
save changes before reset
iLLiCiTiT Jul 14, 2022
36ae9ff
added some docstring to plugin
iLLiCiTiT Jul 14, 2022
8083c1e
remove not relevant lines
iLLiCiTiT Jul 14, 2022
b5fa8b5
unify imports
iLLiCiTiT Jul 14, 2022
7729d53
files item can have custom extensions label
iLLiCiTiT Jul 14, 2022
1baf045
added second file input for reviewables
iLLiCiTiT Jul 14, 2022
8a6ee91
removed reviewable key from settings (unused)
iLLiCiTiT Jul 14, 2022
64b4bda
handle review representations using reviewable file input
iLLiCiTiT Jul 14, 2022
1561a47
changed key 'filepath' to 'representation_files'
iLLiCiTiT Jul 14, 2022
2b1654a
fix variable usage
iLLiCiTiT Jul 14, 2022
9749286
modified docstring
iLLiCiTiT Jul 14, 2022
f346fb8
implemented helper function for loading of internal data
iLLiCiTiT Jul 14, 2022
ef51503
added helper method for conversion of data to bytes
iLLiCiTiT Jul 14, 2022
53dd6cf
it is possible to move file items across widgets
iLLiCiTiT Jul 14, 2022
9a83b83
it is possible to copy file items
iLLiCiTiT Jul 14, 2022
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
40 changes: 37 additions & 3 deletions openpype/hosts/traypublisher/api/plugin.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from openpype.lib.attribute_definitions import FileDef
from openpype.pipeline import (
Creator,
CreatedInstance
)
from openpype.lib import FileDef

from .pipeline import (
list_instances,
Expand All @@ -12,6 +12,29 @@
)


IMAGE_EXTENSIONS = [
".ani", ".anim", ".apng", ".art", ".bmp", ".bpg", ".bsave", ".cal",
".cin", ".cpc", ".cpt", ".dds", ".dpx", ".ecw", ".exr", ".fits",
".flic", ".flif", ".fpx", ".gif", ".hdri", ".hevc", ".icer",
".icns", ".ico", ".cur", ".ics", ".ilbm", ".jbig", ".jbig2",
".jng", ".jpeg", ".jpeg-ls", ".jpeg", ".2000", ".jpg", ".xr",
".jpeg", ".xt", ".jpeg-hdr", ".kra", ".mng", ".miff", ".nrrd",
".ora", ".pam", ".pbm", ".pgm", ".ppm", ".pnm", ".pcx", ".pgf",
".pictor", ".png", ".psb", ".psp", ".qtvr", ".ras",
".rgbe", ".logluv", ".tiff", ".sgi", ".tga", ".tiff", ".tiff/ep",
".tiff/it", ".ufo", ".ufp", ".wbmp", ".webp", ".xbm", ".xcf",
".xpm", ".xwd"
]
VIDEO_EXTENSIONS = [
".3g2", ".3gp", ".amv", ".asf", ".avi", ".drc", ".f4a", ".f4b",
".f4p", ".f4v", ".flv", ".gif", ".gifv", ".m2v", ".m4p", ".m4v",
".mkv", ".mng", ".mov", ".mp2", ".mp4", ".mpe", ".mpeg", ".mpg",
".mpv", ".mxf", ".nsv", ".ogg", ".ogv", ".qt", ".rm", ".rmvb",
".roq", ".svi", ".vob", ".webm", ".wmv", ".yuv"
]
REVIEW_EXTENSIONS = IMAGE_EXTENSIONS + VIDEO_EXTENSIONS


class TrayPublishCreator(Creator):
create_allow_context_change = True
host_name = "traypublisher"
Expand Down Expand Up @@ -79,11 +102,21 @@ def create(self, subset_name, data, pre_create_data):
def get_instance_attr_defs(self):
return [
FileDef(
"filepath",
"representation_files",
folders=False,
extensions=self.extensions,
allow_sequences=self.allow_sequences,
label="Filepath",
single_item=not self.allow_multiple_items,
label="Representations",
),
FileDef(
"reviewable",
folders=False,
extensions=REVIEW_EXTENSIONS,
allow_sequences=True,
single_item=True,
label="Reviewable representations",
extensions_label="Single reviewable item"
)
]

Expand All @@ -105,6 +138,7 @@ def from_settings(cls, item_data):
"detailed_description": item_data["detailed_description"],
"extensions": item_data["extensions"],
"allow_sequences": item_data["allow_sequences"],
"allow_multiple_items": item_data["allow_multiple_items"],
"default_variants": item_data["default_variants"]
}
)

This file was deleted.

228 changes: 197 additions & 31 deletions openpype/hosts/traypublisher/plugins/publish/collect_simple_instances.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,31 @@
import os
import tempfile

import clique
import pyblish.api


class CollectSettingsSimpleInstances(pyblish.api.InstancePlugin):
"""Collect data for instances created by settings creators."""
"""Collect data for instances created by settings creators.

Plugin create representations for simple instances based
on 'representation_files' attribute stored on instance data.

There is also possibility to have reviewable representation which can be
stored under 'reviewable' attribute stored on instance data. If there was
already created representation with the same files as 'revieable' containes

Representations can be marked for review and in that case is also added
'review' family to instance families. For review can be marked only one
representation so **first** representation that has extension available
in '_review_extensions' is used for review.

For instance 'source' is used path from last representation created
from 'representation_files'.

Set staging directory on instance. That is probably never used because
each created representation has it's own staging dir.
"""

label = "Collect Settings Simple Instances"
order = pyblish.api.CollectorOrder - 0.49
Expand All @@ -16,47 +36,193 @@ def process(self, instance):
if not instance.data.get("settings_creator"):
return

if "families" not in instance.data:
instance.data["families"] = []
instance_label = instance.data["name"]
# Create instance's staging dir in temp
tmp_folder = tempfile.mkdtemp(prefix="traypublisher_")
instance.data["stagingDir"] = tmp_folder
instance.context.data["cleanupFullPaths"].append(tmp_folder)

self.log.debug((
"Created temp staging directory for instance {}. {}"
).format(instance_label, tmp_folder))

# Store filepaths for validation of their existence
source_filepaths = []
# Make sure there are no representations with same name
repre_names_counter = {}
# Store created names for logging
repre_names = []
# Store set of filepaths per each representation
representation_files_mapping = []
source = self._create_main_representations(
instance,
source_filepaths,
repre_names_counter,
repre_names,
representation_files_mapping
)

self._create_review_representation(
instance,
source_filepaths,
repre_names_counter,
repre_names,
representation_files_mapping
)

instance.data["source"] = source
instance.data["sourceFilepaths"] = list(set(source_filepaths))

if "representations" not in instance.data:
instance.data["representations"] = []
repres = instance.data["representations"]
self.log.debug(
(
"Created Simple Settings instance \"{}\""
" with {} representations: {}"
).format(
instance_label,
len(instance.data["representations"]),
", ".join(repre_names)
)
)

def _create_main_representations(
self,
instance,
source_filepaths,
repre_names_counter,
repre_names,
representation_files_mapping
):
creator_attributes = instance.data["creator_attributes"]
filepath_item = creator_attributes["filepath"]
self.log.info(filepath_item)
filepaths = [
os.path.join(filepath_item["directory"], filename)
for filename in filepath_item["filenames"]
]
filepath_items = creator_attributes["representation_files"]
if not isinstance(filepath_items, list):
filepath_items = [filepath_items]

cols, rems = clique.assemble(filepaths)
source = None
if cols:
source = cols[0].format("{head}{padding}{tail}")
elif rems:
source = rems[0]
for filepath_item in filepath_items:
# Skip if filepath item does not have filenames
if not filepath_item["filenames"]:
continue

instance.data["source"] = source
instance.data["sourceFilepaths"] = filepaths
instance.data["stagingDir"] = filepath_item["directory"]
filepaths = {
os.path.join(filepath_item["directory"], filename)
for filename in filepath_item["filenames"]
}
source_filepaths.extend(filepaths)

source = self._calculate_source(filepaths)
representation = self._create_representation_data(
filepath_item, repre_names_counter, repre_names
)
instance.data["representations"].append(representation)
representation_files_mapping.append(
(filepaths, representation, source)
)
return source

def _create_review_representation(
self,
instance,
source_filepaths,
repre_names_counter,
repre_names,
representation_files_mapping
):
# Skip review representation creation if there are no representations
# created for "main" part
# - review representation must not be created in that case so
# validation can care about it
if not representation_files_mapping:
self.log.warning((
"There are missing source representations."
" Creation of review representation was skipped."
))
return

creator_attributes = instance.data["creator_attributes"]
review_file_item = creator_attributes["reviewable"]
filenames = review_file_item.get("filenames")
if not filenames:
self.log.debug((
"Filepath for review is not defined."
" Skipping review representation creation."
))
return

filepaths = {
os.path.join(review_file_item["directory"], filename)
for filename in filenames
}
source_filepaths.extend(filepaths)
# First try to find out representation with same filepaths
# so it's not needed to create new representation just for review
review_representation = None
# Review path (only for logging)
review_path = None
for item in representation_files_mapping:
_filepaths, representation, repre_path = item
if _filepaths == filepaths:
review_representation = representation
review_path = repre_path
break

if review_representation is None:
self.log.debug("Creating new review representation")
review_path = self._calculate_source(filepaths)
review_representation = self._create_representation_data(
review_file_item, repre_names_counter, repre_names
)
instance.data["representations"].append(review_representation)

if "review" not in instance.data["families"]:
instance.data["families"].append("review")

review_representation["tags"].append("review")
self.log.debug("Representation {} was marked for review. {}".format(
review_representation["name"], review_path
))

def _create_representation_data(
self, filepath_item, repre_names_counter, repre_names
):
"""Create new representation data based on file item.

Args:
filepath_item (Dict[str, Any]): Item with information about
representation paths.
repre_names_counter (Dict[str, int]): Store count of representation
names.
repre_names (List[str]): All used representation names. For
logging purposes.

Returns:
Dict: Prepared base representation data.
"""

filenames = filepath_item["filenames"]
_, ext = os.path.splitext(filenames[0])
ext = ext[1:]
if len(filenames) == 1:
filenames = filenames[0]

repres.append({
"ext": ext,
"name": ext,
repre_name = repre_ext = ext[1:]
if repre_name not in repre_names_counter:
repre_names_counter[repre_name] = 2
else:
counter = repre_names_counter[repre_name]
repre_names_counter[repre_name] += 1
repre_name = "{}_{}".format(repre_name, counter)
repre_names.append(repre_name)
return {
"ext": repre_ext,
"name": repre_name,
"stagingDir": filepath_item["directory"],
"files": filenames
})

instance.data["source"] = "\n".join(filepaths)
"files": filenames,
"tags": []
}

self.log.debug("Created Simple Settings instance {}".format(
instance.data
))
def _calculate_source(self, filepaths):
cols, rems = clique.assemble(filepaths)
if cols:
source = cols[0].format("{head}{padding}{tail}")
elif rems:
source = rems[0]
return source
Loading