From eedc67edcc37dcfeae0254e4e856ec4b7df409cf Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 4 Jul 2022 16:28:59 +0200 Subject: [PATCH 01/51] use project entity from context instead of requery --- .../deadline/plugins/publish/submit_houdini_remote_publish.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_houdini_remote_publish.py b/openpype/modules/deadline/plugins/publish/submit_houdini_remote_publish.py index f834ae7e92..fdf67b51bc 100644 --- a/openpype/modules/deadline/plugins/publish/submit_houdini_remote_publish.py +++ b/openpype/modules/deadline/plugins/publish/submit_houdini_remote_publish.py @@ -55,7 +55,7 @@ class HoudiniSubmitPublishDeadline(pyblish.api.ContextPlugin): scenename = os.path.basename(scene) # Get project code - project = legacy_io.find_one({"type": "project"}) + project = context.data["projectEntity"] code = project["data"].get("code", project["name"]) job_name = "{scene} [PUBLISH]".format(scene=scenename) From 5ba81e8c284e9ee38ceb84dae2aee25d054f8685 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 4 Jul 2022 16:37:36 +0200 Subject: [PATCH 02/51] use query function in submit to deadline --- .../plugins/publish/submit_publish_job.py | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_publish_job.py b/openpype/modules/deadline/plugins/publish/submit_publish_job.py index 9dd1428a63..b098eaba8e 100644 --- a/openpype/modules/deadline/plugins/publish/submit_publish_job.py +++ b/openpype/modules/deadline/plugins/publish/submit_publish_job.py @@ -11,6 +11,7 @@ import clique import pyblish.api import openpype.api +from openpype.client import get_representations from openpype.pipeline import ( get_representation_path, legacy_io, @@ -18,15 +19,23 @@ from openpype.pipeline import ( from openpype.pipeline.farm.patterning import match_aov_pattern -def get_resources(version, extension=None): +def get_resources(project_name, version, extension=None): """Get the files from the specific version.""" - query = {"type": "representation", "parent": version["_id"]} + + # TODO this functions seems to be weird + # - it's looking for representation with one extension or first (any) + # representation from a version? + # - not sure how this should work, maybe it does for specific use cases + # but probably can't be used for all resources from 2D workflows + extensions = None if extension: - query["name"] = extension - - representation = legacy_io.find_one(query) - assert representation, "This is a bug" + extensions = [extension] + repre_docs = list(get_representations( + project_name, version_ids=[version["_id"]], extensions=extensions + )) + assert repre_docs, "This is a bug" + representation = repre_docs[0] directory = get_representation_path(representation) print("Source: ", directory) resources = sorted( @@ -330,13 +339,16 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): self.log.info("Preparing to copy ...") start = instance.data.get("frameStart") end = instance.data.get("frameEnd") + project_name = legacy_io.active_project() # get latest version of subset # this will stop if subset wasn't published yet version = openpype.api.get_latest_version(instance.data.get("asset"), instance.data.get("subset")) # get its files based on extension - subset_resources = get_resources(version, representation.get("ext")) + subset_resources = get_resources( + project_name, version, representation.get("ext") + ) r_col, _ = clique.assemble(subset_resources) # if override remove all frames we are expecting to be rendered From 74e57f9f49cdbb4812cd6d0c5348c5877f4e61e1 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 11 Jul 2022 18:15:46 +0200 Subject: [PATCH 03/51] OP-3446 - implemented render_mov_batch in TrayPublisher --- openpype/hosts/traypublisher/api/batch_lib.py | 61 ++++++ .../plugins/create/create_mov_batch.py | 191 ++++++++++++++++++ .../plugins/publish/collect_mov_batch.py | 34 ++++ .../project_settings/traypublisher.json | 15 +- .../schema_project_traypublisher.json | 71 +++++++ 5 files changed, 371 insertions(+), 1 deletion(-) create mode 100644 openpype/hosts/traypublisher/api/batch_lib.py create mode 100644 openpype/hosts/traypublisher/plugins/create/create_mov_batch.py create mode 100644 openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py diff --git a/openpype/hosts/traypublisher/api/batch_lib.py b/openpype/hosts/traypublisher/api/batch_lib.py new file mode 100644 index 0000000000..2486d405bd --- /dev/null +++ b/openpype/hosts/traypublisher/api/batch_lib.py @@ -0,0 +1,61 @@ +# Helper functions to find matching asset for (multiple) processed source files +import os +import collections + +from openpype.client import get_assets + + +def get_children_assets_by_name(project_name, top_asset_doc): + """ Get all children for 'top_asset_doc' by theirs name + + Args: + project_name (str) + top_asset_doc (asset doc) (eg dict) + Returns: + (dict) {"shot1": shot1_asset_doc} + """ + assets_by_parent_id = get_asset_docs_by_parent_id(project_name) + _children_docs = get_children_docs( + assets_by_parent_id, top_asset_doc + ) + children_docs = { + children_doc["name"].lower(): children_doc + for children_doc in _children_docs + } + return children_docs + + +def get_asset_docs_by_parent_id(project_name): + """ Query all assets for project and store them by parent's id to list + + Args: + project_name (str) + Returns: + (dict) { _id of parent :[asset_doc1, asset_doc2]} + """ + asset_docs_by_parent_id = collections.defaultdict(list) + for asset_doc in get_assets(project_name): + parent_id = asset_doc["data"]["visualParent"] + asset_docs_by_parent_id[parent_id].append(asset_doc) + return asset_docs_by_parent_id + + +def get_children_docs(documents_by_parent_id, parent_doc): + """ Recursively find all children in reverse order + + Last children first. + Args: + documents_by_parent_id (dict) + parent_doc (asset doc, eg dict) + Returns + (list) of asset docs + """ + output = [] + children = documents_by_parent_id.get(parent_doc["_id"]) or tuple() + for child in children: + output.extend( + get_children_docs(documents_by_parent_id, child) + ) + output.append(parent_doc) + return output + diff --git a/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py b/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py new file mode 100644 index 0000000000..5297d73ba9 --- /dev/null +++ b/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py @@ -0,0 +1,191 @@ +import copy +import os +import re + +from openpype.client import get_assets +from openpype.hosts.traypublisher.api import pipeline +from openpype.lib import FileDef, TextDef, get_subset_name_with_asset_doc +from openpype.pipeline import ( + CreatedInstance +) + +from openpype.hosts.traypublisher.api.plugin import TrayPublishCreator + + +class BatchMovCreator(TrayPublishCreator): + """Creates instances from .mov file(s).""" + identifier = "render_mov_batch" + label = "Batch Mov" + family = "render" + description = "Publish batch of movs" + host_name = "traypublisher" + + create_allow_context_change = False + version_regex = re.compile(r"^(.+)_v([0-9]+)$") + + default_tasks = ["Compositing"] + + extensions = [".mov"] + + def __init__(self, project_settings, *args, **kwargs): + super(BatchMovCreator, self).__init__(project_settings, + *args, **kwargs) + self._default_variants = (project_settings["traypublisher"] + ["BatchMovCreator"] + ["default_variants"]) + + def get_icon(self): + return "fa.file" + + def create(self, subset_name, data, pre_create_data): + file_paths = pre_create_data.get("filepath") + if not file_paths: + return + + for file_info in file_paths: + instance_data = copy.deepcopy(data) + file_name = file_info["filenames"][0] + filepath = os.path.join(file_info["directory"], file_name) + instance_data["creator_attributes"] = {"filepath": filepath} + + asset_doc, version = self.get_asset_doc_from_file_name( + file_name, self.project_name) + + subset_name, task_name = self._get_subset_and_task( + asset_doc, data["variant"], self.project_name) + + instance_data["task"] = task_name + instance_data["asset"] = asset_doc["name"] + + # Create new instance + new_instance = CreatedInstance(self.family, subset_name, + instance_data, self) + # Host implementation of storing metadata about instance + pipeline.HostContext.add_instance(new_instance.data_to_store()) + # Add instance to current context + self._add_instance_to_context(new_instance) + + def get_asset_doc_from_file_name(self, source_filename, project_name): + """Try to parse out asset name from file name provided. + + Artists might provide various file name formats. + Currently handled: + - chair.mov + - chair_v001.mov + - my_chair_to_upload.mov + """ + version = None + asset_name = os.path.splitext(source_filename)[0] + # Always first check if source filename is in assets + matching_asset_doc = self._get_asset_by_name_case_not_sensitive( + project_name, asset_name) + + if matching_asset_doc is None: + matching_asset_doc, version = ( + self._parse_with_version(project_name, asset_name)) + + if matching_asset_doc is None: + matching_asset_doc = self._parse_containing(project_name, + asset_name) + + if matching_asset_doc is None: + raise ValueError( + "Cannot guess asset name from {}".format(source_filename)) + + return matching_asset_doc, version + + def _parse_with_version(self, project_name, asset_name): + """Try to parse asset name from a file name containing version too + + Eg. 'chair_v001.mov' >> 'chair', 1 + """ + self.log.debug(( + "Asset doc by \"{}\" was not found, trying version regex." + ).format(asset_name)) + + matching_asset_doc = version_number = None + + regex_result = self.version_regex.findall(asset_name) + if regex_result: + _asset_name, _version_number = regex_result[0] + matching_asset_doc = self._get_asset_by_name_case_not_sensitive( + project_name, _asset_name) + if matching_asset_doc: + version_number = int(_version_number) + + return matching_asset_doc, version_number + + def _parse_containing(self, project_name, asset_name): + """Look if file name contains any existing asset name""" + for asset_doc in get_assets(project_name, fields=["name"]): + if asset_doc["name"].lower() in asset_name.lower(): + return get_assets(project_name, + asset_names=[asset_doc["name"]]) + + def _get_subset_and_task(self, asset_doc, variant, project_name): + """Create subset name according to standard template process""" + task_name = self._get_task_name(asset_doc) + + subset_name = get_subset_name_with_asset_doc( + self.family, + variant, + task_name, + asset_doc, + project_name + ) + + return subset_name, task_name + + def _get_task_name(self, asset_doc): + """Get applicable task from 'asset_doc' """ + available_task_names = {} + asset_tasks = asset_doc.get("data", {}).get("tasks") or {} + for task_name in asset_tasks.keys(): + available_task_names[task_name.lower()] = task_name + + task_name = None + for _task_name in self.default_tasks: + _task_name_low = _task_name.lower() + if _task_name_low in available_task_names: + task_name = available_task_names[_task_name_low] + break + + return task_name + + def get_default_variants(self): + return self._default_variants + + def get_instance_attr_defs(self): + return [] + + def get_pre_create_attr_defs(self): + # Use same attributes as for instance attributes + return [ + FileDef( + "filepath", + folders=False, + single_item=False, + extensions=self.extensions, + label="Filepath" + ) + ] + + def get_detail_description(self): + return """# Publish batch of .mov to multiple assets. + + File names must then contain only asset name, or asset name + version. + (eg. 'chair.mov', 'chair_v001.mov', not really safe `my_chair_v001.mov` + """ + + def _get_asset_by_name_case_not_sensitive(self, project_name, asset_name): + """Handle more cases in file names""" + asset_name = re.compile(asset_name, re.IGNORECASE) + + assets = list(get_assets(project_name, asset_names=[asset_name])) + if assets: + if len(assets) > 1: + self.log.warning("Too many records found for {}".format( + asset_name)) + return + + return assets.pop() diff --git a/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py b/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py new file mode 100644 index 0000000000..2a5e356684 --- /dev/null +++ b/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py @@ -0,0 +1,34 @@ +import os + +import pyblish.api +from openpype.pipeline import OpenPypePyblishPluginMixin + + +class CollectMovBatch( + pyblish.api.InstancePlugin, OpenPypePyblishPluginMixin +): + """Collect file url for batch mov and create representation.""" + + label = "Collect Mov Batch Files" + order = pyblish.api.CollectorOrder + + hosts = ["traypublisher"] + + def process(self, instance): + if not instance.data.get("creator_identifier") == "render_mov_batch": + return + + file_url = instance.data["creator_attributes"]["filepath"] + file_name = os.path.basename(file_url) + _, ext = os.path.splitext(file_name) + + repre = { + "name": ext[1:], + "ext": ext[1:], + "files": file_name, + "stagingDir": os.path.dirname(file_url) + } + + instance.data["representations"].append(repre) + + self.log.debug("instance.data {}".format(instance.data)) diff --git a/openpype/settings/defaults/project_settings/traypublisher.json b/openpype/settings/defaults/project_settings/traypublisher.json index 0b54cfd39e..6d2d32a037 100644 --- a/openpype/settings/defaults/project_settings/traypublisher.json +++ b/openpype/settings/defaults/project_settings/traypublisher.json @@ -31,5 +31,18 @@ ".aep" ] } - ] + ], + "BatchMovCreator": { + "family": "render_mov_batch", + "identifier": "", + "label": "Batch Mov", + "icon": "fa.file", + "default_variants": [], + "description": "", + "detailed_description": "", + "default_tasks": "Compositing", + "extensions": [ + ".mov" + ] + } } \ No newline at end of file diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json b/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json index 55c1b7b7d7..7cb74d86a7 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json @@ -78,6 +78,77 @@ } ] } + }, + { + "type": "dict", + "collapsible": true, + "key": "BatchMovCreator", + "label": "Batch Mov Creator", + "use_label_wrap": true, + "collapsible_key": true, + "children": [ + { + "type": "text", + "key": "family", + "label": "Family" + }, + { + "type": "text", + "key": "identifier", + "label": "Identifier", + "placeholder": "< Use 'Family' >", + "tooltip": "All creators must have unique identifier.\nBy default is used 'family' but if you need to have more creators with same families\nyou have to set identifier too." + }, + { + "type": "text", + "key": "label", + "label": "Label" + }, + { + "type": "text", + "key": "icon", + "label": "Icon" + }, + { + "type": "list", + "key": "default_variants", + "label": "Default variants", + "object_type": { + "type": "text" + } + }, + { + "type": "separator" + }, + { + "type": "text", + "key": "description", + "label": "Description" + }, + { + "type": "text", + "key": "detailed_description", + "label": "Detailed Description", + "multiline": true + }, + { + "type": "separator" + }, + { + "type": "text", + "key": "default_tasks", + "label": "Default task" + }, + { + "type": "list", + "key": "extensions", + "label": "Extensions", + "use_label_wrap": true, + "collapsible_key": true, + "collapsed": false, + "object_type": "text" + } + ] } ] } From a7c945f51f484a848401072fd230334710f3b734 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 12 Jul 2022 11:01:52 +0200 Subject: [PATCH 04/51] OP-3446 - fix return type --- .../traypublisher/plugins/create/create_mov_batch.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py b/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py index 5297d73ba9..d796b304a3 100644 --- a/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py +++ b/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py @@ -2,11 +2,12 @@ import copy import os import re -from openpype.client import get_assets +from openpype.client import get_assets, get_asset_by_name from openpype.hosts.traypublisher.api import pipeline -from openpype.lib import FileDef, TextDef, get_subset_name_with_asset_doc +from openpype.lib import FileDef, get_subset_name_with_asset_doc from openpype.pipeline import ( - CreatedInstance + CreatedInstance, + CreatorError ) from openpype.hosts.traypublisher.api.plugin import TrayPublishCreator @@ -89,7 +90,7 @@ class BatchMovCreator(TrayPublishCreator): asset_name) if matching_asset_doc is None: - raise ValueError( + raise CreatorError( "Cannot guess asset name from {}".format(source_filename)) return matching_asset_doc, version @@ -119,8 +120,7 @@ class BatchMovCreator(TrayPublishCreator): """Look if file name contains any existing asset name""" for asset_doc in get_assets(project_name, fields=["name"]): if asset_doc["name"].lower() in asset_name.lower(): - return get_assets(project_name, - asset_names=[asset_doc["name"]]) + return get_asset_by_name(project_name, asset_doc["name"]) def _get_subset_and_task(self, asset_doc, variant, project_name): """Create subset name according to standard template process""" From c3384c4005132c2eb973d0bda8a191bb3fd6791c Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 12 Jul 2022 11:02:06 +0200 Subject: [PATCH 05/51] OP-3446 - remove obsolete methods --- openpype/hosts/traypublisher/api/batch_lib.py | 61 ------------------- 1 file changed, 61 deletions(-) delete mode 100644 openpype/hosts/traypublisher/api/batch_lib.py diff --git a/openpype/hosts/traypublisher/api/batch_lib.py b/openpype/hosts/traypublisher/api/batch_lib.py deleted file mode 100644 index 2486d405bd..0000000000 --- a/openpype/hosts/traypublisher/api/batch_lib.py +++ /dev/null @@ -1,61 +0,0 @@ -# Helper functions to find matching asset for (multiple) processed source files -import os -import collections - -from openpype.client import get_assets - - -def get_children_assets_by_name(project_name, top_asset_doc): - """ Get all children for 'top_asset_doc' by theirs name - - Args: - project_name (str) - top_asset_doc (asset doc) (eg dict) - Returns: - (dict) {"shot1": shot1_asset_doc} - """ - assets_by_parent_id = get_asset_docs_by_parent_id(project_name) - _children_docs = get_children_docs( - assets_by_parent_id, top_asset_doc - ) - children_docs = { - children_doc["name"].lower(): children_doc - for children_doc in _children_docs - } - return children_docs - - -def get_asset_docs_by_parent_id(project_name): - """ Query all assets for project and store them by parent's id to list - - Args: - project_name (str) - Returns: - (dict) { _id of parent :[asset_doc1, asset_doc2]} - """ - asset_docs_by_parent_id = collections.defaultdict(list) - for asset_doc in get_assets(project_name): - parent_id = asset_doc["data"]["visualParent"] - asset_docs_by_parent_id[parent_id].append(asset_doc) - return asset_docs_by_parent_id - - -def get_children_docs(documents_by_parent_id, parent_doc): - """ Recursively find all children in reverse order - - Last children first. - Args: - documents_by_parent_id (dict) - parent_doc (asset doc, eg dict) - Returns - (list) of asset docs - """ - output = [] - children = documents_by_parent_id.get(parent_doc["_id"]) or tuple() - for child in children: - output.extend( - get_children_docs(documents_by_parent_id, child) - ) - output.append(parent_doc) - return output - From 24e26ce63a478941dd4334c7558b92c5eb853b95 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 12 Jul 2022 11:05:35 +0200 Subject: [PATCH 06/51] OP-3446 - fill defaults_variant explicitly No need to overwrite method --- .../traypublisher/plugins/create/create_mov_batch.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py b/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py index d796b304a3..1577b622ab 100644 --- a/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py +++ b/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py @@ -31,9 +31,9 @@ class BatchMovCreator(TrayPublishCreator): def __init__(self, project_settings, *args, **kwargs): super(BatchMovCreator, self).__init__(project_settings, *args, **kwargs) - self._default_variants = (project_settings["traypublisher"] - ["BatchMovCreator"] - ["default_variants"]) + self.default_variants = (project_settings["traypublisher"] + ["BatchMovCreator"] + ["default_variants"]) def get_icon(self): return "fa.file" @@ -152,9 +152,6 @@ class BatchMovCreator(TrayPublishCreator): return task_name - def get_default_variants(self): - return self._default_variants - def get_instance_attr_defs(self): return [] From 89eddfa63d91eb1de766363b9d9c8c7899d39ad1 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 12 Jul 2022 11:17:55 +0200 Subject: [PATCH 07/51] OP-3446 - fix pulling configuration from Settings --- .../traypublisher/plugins/create/create_mov_batch.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py b/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py index 1577b622ab..e54fc44acc 100644 --- a/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py +++ b/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py @@ -24,10 +24,6 @@ class BatchMovCreator(TrayPublishCreator): create_allow_context_change = False version_regex = re.compile(r"^(.+)_v([0-9]+)$") - default_tasks = ["Compositing"] - - extensions = [".mov"] - def __init__(self, project_settings, *args, **kwargs): super(BatchMovCreator, self).__init__(project_settings, *args, **kwargs) @@ -35,6 +31,14 @@ class BatchMovCreator(TrayPublishCreator): ["BatchMovCreator"] ["default_variants"]) + self.default_tasks = (project_settings["traypublisher"] + ["BatchMovCreator"] + ["default_tasks"]) + + self.extensions = (project_settings["traypublisher"] + ["BatchMovCreator"] + ["extensions"]) + def get_icon(self): return "fa.file" From 1fe8c96c261e9687b5aaca52e53d88897fef540a Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 12 Jul 2022 11:18:31 +0200 Subject: [PATCH 08/51] OP-3446 - modifying Settings to list --- .../settings/defaults/project_settings/traypublisher.json | 4 ++-- .../projects_schema/schema_project_traypublisher.json | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/openpype/settings/defaults/project_settings/traypublisher.json b/openpype/settings/defaults/project_settings/traypublisher.json index 6d2d32a037..36526d01b0 100644 --- a/openpype/settings/defaults/project_settings/traypublisher.json +++ b/openpype/settings/defaults/project_settings/traypublisher.json @@ -37,10 +37,10 @@ "identifier": "", "label": "Batch Mov", "icon": "fa.file", - "default_variants": [], + "default_variants": ["Main"], "description": "", "detailed_description": "", - "default_tasks": "Compositing", + "default_tasks": ["Compositing"], "extensions": [ ".mov" ] diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json b/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json index 7cb74d86a7..308883d46f 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json @@ -135,9 +135,12 @@ "type": "separator" }, { - "type": "text", + "type": "list", "key": "default_tasks", - "label": "Default task" + "label": "Default tasks", + "object_type": { + "type": "text" + } }, { "type": "list", From 20b0292af170360db2aecb0483afe3ae13dd3bcd Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 12 Jul 2022 11:19:27 +0200 Subject: [PATCH 09/51] OP-3446 - removed unneeded, comes from class --- openpype/hosts/traypublisher/plugins/create/create_mov_batch.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py b/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py index e54fc44acc..fdada96c87 100644 --- a/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py +++ b/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py @@ -19,7 +19,6 @@ class BatchMovCreator(TrayPublishCreator): label = "Batch Mov" family = "render" description = "Publish batch of movs" - host_name = "traypublisher" create_allow_context_change = False version_regex = re.compile(r"^(.+)_v([0-9]+)$") From 636206f9d2bab1e22337ebbd09c7db68b99e2fa2 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 12 Jul 2022 12:19:22 +0200 Subject: [PATCH 10/51] Update openpype/hosts/traypublisher/plugins/create/create_mov_batch.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- .../plugins/create/create_mov_batch.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py b/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py index fdada96c87..20d3ecbd7c 100644 --- a/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py +++ b/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py @@ -26,17 +26,12 @@ class BatchMovCreator(TrayPublishCreator): def __init__(self, project_settings, *args, **kwargs): super(BatchMovCreator, self).__init__(project_settings, *args, **kwargs) - self.default_variants = (project_settings["traypublisher"] - ["BatchMovCreator"] - ["default_variants"]) - - self.default_tasks = (project_settings["traypublisher"] - ["BatchMovCreator"] - ["default_tasks"]) - - self.extensions = (project_settings["traypublisher"] - ["BatchMovCreator"] - ["extensions"]) + creator_settings = ( + project_settings["traypublisher"]["BatchMovCreator"] + ) + self.default_variants = creator_settings["default_variants"] + self.default_tasks = creator_settings["default_tasks"] + self.extensions = creator_settings["extensions"] def get_icon(self): return "fa.file" From bfd565e29d40f0daca2ddbdb01d036d9dc6b543a Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 12 Jul 2022 17:57:07 +0200 Subject: [PATCH 11/51] OP-3446 - add traypublisher to host enum --- openpype/settings/entities/enum_entity.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/settings/entities/enum_entity.py b/openpype/settings/entities/enum_entity.py index 92a397afba..03998677ce 100644 --- a/openpype/settings/entities/enum_entity.py +++ b/openpype/settings/entities/enum_entity.py @@ -169,6 +169,7 @@ class HostsEnumEntity(BaseEnumEntity): "tvpaint", "unreal", "standalonepublisher", + "traypublisher", "webpublisher" ] From 4fe4ac163e96d7a08cce31d30a8d8fdb85b35cc1 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 12 Jul 2022 17:57:47 +0200 Subject: [PATCH 12/51] OP-3446 - add traypublisher ftrack setting --- .../defaults/project_settings/ftrack.json | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/openpype/settings/defaults/project_settings/ftrack.json b/openpype/settings/defaults/project_settings/ftrack.json index 831c34835e..eb90778353 100644 --- a/openpype/settings/defaults/project_settings/ftrack.json +++ b/openpype/settings/defaults/project_settings/ftrack.json @@ -268,6 +268,49 @@ } ] }, + { + "hosts": [ + "traypublisher" + ], + "families": [], + "task_types": [], + "tasks": [], + "add_ftrack_family": true, + "advanced_filtering": [] + }, + { + "hosts": [ + "traypublisher" + ], + "families": [ + "matchmove", + "shot" + ], + "task_types": [], + "tasks": [], + "add_ftrack_family": false, + "advanced_filtering": [] + }, + { + "hosts": [ + "traypublisher" + ], + "families": [ + "plate" + ], + "task_types": [], + "tasks": [], + "add_ftrack_family": false, + "advanced_filtering": [ + { + "families": [ + "clip", + "review" + ], + "add_ftrack_family": true + } + ] + }, { "hosts": [ "maya" From cec639cf7ed62ed28b37c4839752e72d0e845e9b Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 12 Jul 2022 18:04:55 +0200 Subject: [PATCH 13/51] OP-3446 - updated settings for TrayPublisher --- .../project_settings/traypublisher.json | 6 --- .../schema_project_traypublisher.json | 39 ------------------- 2 files changed, 45 deletions(-) diff --git a/openpype/settings/defaults/project_settings/traypublisher.json b/openpype/settings/defaults/project_settings/traypublisher.json index 36526d01b0..cb3d3d1d1a 100644 --- a/openpype/settings/defaults/project_settings/traypublisher.json +++ b/openpype/settings/defaults/project_settings/traypublisher.json @@ -33,13 +33,7 @@ } ], "BatchMovCreator": { - "family": "render_mov_batch", - "identifier": "", - "label": "Batch Mov", - "icon": "fa.file", "default_variants": ["Main"], - "description": "", - "detailed_description": "", "default_tasks": ["Compositing"], "extensions": [ ".mov" diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json b/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json index 308883d46f..d4ad57767a 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json @@ -87,28 +87,6 @@ "use_label_wrap": true, "collapsible_key": true, "children": [ - { - "type": "text", - "key": "family", - "label": "Family" - }, - { - "type": "text", - "key": "identifier", - "label": "Identifier", - "placeholder": "< Use 'Family' >", - "tooltip": "All creators must have unique identifier.\nBy default is used 'family' but if you need to have more creators with same families\nyou have to set identifier too." - }, - { - "type": "text", - "key": "label", - "label": "Label" - }, - { - "type": "text", - "key": "icon", - "label": "Icon" - }, { "type": "list", "key": "default_variants", @@ -117,23 +95,6 @@ "type": "text" } }, - { - "type": "separator" - }, - { - "type": "text", - "key": "description", - "label": "Description" - }, - { - "type": "text", - "key": "detailed_description", - "label": "Detailed Description", - "multiline": true - }, - { - "type": "separator" - }, { "type": "list", "key": "default_tasks", From 8bbf693a92a247894a10ef531ac433b3740ac154 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 13 Jul 2022 09:03:41 +0200 Subject: [PATCH 14/51] add unpack and pack tools --- tools/pack_project.ps1 | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 tools/pack_project.ps1 diff --git a/tools/pack_project.ps1 b/tools/pack_project.ps1 new file mode 100644 index 0000000000..36ec3cb96b --- /dev/null +++ b/tools/pack_project.ps1 @@ -0,0 +1,39 @@ +<# +.SYNOPSIS + Helper script OpenPype Packing project. + +.DESCRIPTION + Once you are happy with the project and want to preserve it for future work, just change the project name on line 38 and copy the file into .\OpenPype\tools. Then use the cmd form .EXAMPLE + +.EXAMPLE + +PS> .\tools\run_pack_project.ps1 + +#> +$current_dir = Get-Location +$script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent +$openpype_root = (Get-Item $script_dir).parent.FullName + +$env:_INSIDE_OPENPYPE_TOOL = "1" + +# make sure Poetry is in PATH +if (-not (Test-Path 'env:POETRY_HOME')) { + $env:POETRY_HOME = "$openpype_root\.poetry" +} +$env:PATH = "$($env:PATH);$($env:POETRY_HOME)\bin" + +Set-Location -Path $openpype_root + +Write-Host ">>> " -NoNewline -ForegroundColor Green +Write-Host "Reading Poetry ... " -NoNewline +if (-not (Test-Path -PathType Container -Path "$($env:POETRY_HOME)\bin")) { + Write-Host "NOT FOUND" -ForegroundColor Yellow + Write-Host "*** " -NoNewline -ForegroundColor Yellow + Write-Host "We need to install Poetry create virtual env first ..." + & "$openpype_root\tools\create_env.ps1" +} else { + Write-Host "OK" -ForegroundColor Green +} + +& "$($env:POETRY_HOME)\bin\poetry" run python "$($openpype_root)\start.py" pack-project --project "OP02_VFX_demo" +Set-Location -Path $current_dir \ No newline at end of file From 9a3a01c9ed6afeec9015b3dd06c5ef2e2438cc60 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 13 Jul 2022 09:03:50 +0200 Subject: [PATCH 15/51] add unpack tool --- tools/unpack_project.ps1.lnk | Bin 0 -> 1426 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tools/unpack_project.ps1.lnk diff --git a/tools/unpack_project.ps1.lnk b/tools/unpack_project.ps1.lnk new file mode 100644 index 0000000000000000000000000000000000000000..56eee50ca235b0ea76eca52ed0040137a07f9786 GIT binary patch literal 1426 zcma)6Nla5w6ulruP?QphqQQWe7!+DM$QVq(Dv(G@^%ueVBh=p-3T^+VzX+HpPPi}< z7aBAqCImFPkOeN(2ohYVi6aX&xO0fcpsBdf6%x;T9cXYNuerk;{<-&^d;4mLC@w7? znrMP+svM<6%7TA?w)yjnZYplvb~woFi%o7mzn%~}7#A{8?TAmKOzZpF$*k#8w`OoE zk#hC=tLrG=Tq;Hn%{!fB;1gB&J(5aws>`pElaeTbevCibt8J2OIf4!+%G}GLS42N7 zqUUdjQINJh5!4B6SkXoqYGs)lM6m(SXzU~5Mh(IWUNBwId5JhPHPj4i0c>6^(^ zOA7FOxN8^ph|;6?mTVJt4FzP`qeky-5duJ+urt0t*ps0d=dq)*dyWFgQ^w61-)Z38 zNURmucUe?tu~wLOA2;Z%0?N8CoGsgn;0jeNQDZD9d{e_5wIfpnd`i?xjqv=4(t`XY zMATufa!xXEx)s7KLt=ItgpC$RI%ElCef3bG2DaYqbIKhmq5F7qiM-SzE07rBRpc~? z?LNgJwKgh#xy2;~bc%{AY(Z!piP7SS|Bx!i5F#$>64_)%Yltz8E5Ik8ApZ@ehW+YY?o$ z$8!ypV>QL*(b?4(H(&9-bYq=AS($M1AOhY51Ee7QHn3R%#E4g-kYBZg?-fxItRC-1 z5rmPTMaQw1q!_ajoYiwAJ#6SLBdms!7+K@pIozvM->5FvUEAJyegoE Date: Wed, 13 Jul 2022 09:19:34 +0200 Subject: [PATCH 16/51] fix forgotten variables --- openpype/lib/project_backpack.py | 2 +- tools/pack_project.ps1 | 2 +- tools/unpack_project.ps1 | 39 +++++++++++++++++++++++++++++++ tools/unpack_project.ps1.lnk | Bin 1426 -> 0 bytes 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 tools/unpack_project.ps1 delete mode 100644 tools/unpack_project.ps1.lnk diff --git a/openpype/lib/project_backpack.py b/openpype/lib/project_backpack.py index f0188e6765..ff2f1d4b88 100644 --- a/openpype/lib/project_backpack.py +++ b/openpype/lib/project_backpack.py @@ -53,7 +53,7 @@ def pack_project(project_name, destination_dir=None): Args: project_name(str): Project that should be packaged. - destination_dir(str): Optinal path where zip will be stored. Project's + destination_dir(str): Optional path where zip will be stored. Project's root is used if not passed. """ print("Creating package of project \"{}\"".format(project_name)) diff --git a/tools/pack_project.ps1 b/tools/pack_project.ps1 index 36ec3cb96b..856247f7ca 100644 --- a/tools/pack_project.ps1 +++ b/tools/pack_project.ps1 @@ -35,5 +35,5 @@ if (-not (Test-Path -PathType Container -Path "$($env:POETRY_HOME)\bin")) { Write-Host "OK" -ForegroundColor Green } -& "$($env:POETRY_HOME)\bin\poetry" run python "$($openpype_root)\start.py" pack-project --project "OP02_VFX_demo" +& "$($env:POETRY_HOME)\bin\poetry" run python "$($openpype_root)\start.py" pack-project --project $ARGS Set-Location -Path $current_dir \ No newline at end of file diff --git a/tools/unpack_project.ps1 b/tools/unpack_project.ps1 new file mode 100644 index 0000000000..e7b9e87a7f --- /dev/null +++ b/tools/unpack_project.ps1 @@ -0,0 +1,39 @@ +<# +.SYNOPSIS + Helper script OpenPype Unpacking project. + +.DESCRIPTION + Make sure you had dropped the project from your db and removed the poject data in case you were having them previously. Then on line 38 change the to any path where the zip with project is - usually we are having it here https://drive.google.com/drive/u/0/folders/0AKE4mxImOsAGUk9PVA . Copy the file into .\OpenPype\tools. Then use the cmd form .EXAMPLE + +.EXAMPLE + +PS> .\tools\run_unpack_project.ps1 + +#> +$current_dir = Get-Location +$script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent +$openpype_root = (Get-Item $script_dir).parent.FullName + +$env:_INSIDE_OPENPYPE_TOOL = "1" + +# make sure Poetry is in PATH +if (-not (Test-Path 'env:POETRY_HOME')) { + $env:POETRY_HOME = "$openpype_root\.poetry" +} +$env:PATH = "$($env:PATH);$($env:POETRY_HOME)\bin" + +Set-Location -Path $openpype_root + +Write-Host ">>> " -NoNewline -ForegroundColor Green +Write-Host "Reading Poetry ... " -NoNewline +if (-not (Test-Path -PathType Container -Path "$($env:POETRY_HOME)\bin")) { + Write-Host "NOT FOUND" -ForegroundColor Yellow + Write-Host "*** " -NoNewline -ForegroundColor Yellow + Write-Host "We need to install Poetry create virtual env first ..." + & "$openpype_root\tools\create_env.ps1" +} else { + Write-Host "OK" -ForegroundColor Green +} + +& "$($env:POETRY_HOME)\bin\poetry" run python "$($openpype_root)\start.py" unpack-project --zipfile $ARGS +Set-Location -Path $current_dir \ No newline at end of file diff --git a/tools/unpack_project.ps1.lnk b/tools/unpack_project.ps1.lnk deleted file mode 100644 index 56eee50ca235b0ea76eca52ed0040137a07f9786..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1426 zcma)6Nla5w6ulruP?QphqQQWe7!+DM$QVq(Dv(G@^%ueVBh=p-3T^+VzX+HpPPi}< z7aBAqCImFPkOeN(2ohYVi6aX&xO0fcpsBdf6%x;T9cXYNuerk;{<-&^d;4mLC@w7? znrMP+svM<6%7TA?w)yjnZYplvb~woFi%o7mzn%~}7#A{8?TAmKOzZpF$*k#8w`OoE zk#hC=tLrG=Tq;Hn%{!fB;1gB&J(5aws>`pElaeTbevCibt8J2OIf4!+%G}GLS42N7 zqUUdjQINJh5!4B6SkXoqYGs)lM6m(SXzU~5Mh(IWUNBwId5JhPHPj4i0c>6^(^ zOA7FOxN8^ph|;6?mTVJt4FzP`qeky-5duJ+urt0t*ps0d=dq)*dyWFgQ^w61-)Z38 zNURmucUe?tu~wLOA2;Z%0?N8CoGsgn;0jeNQDZD9d{e_5wIfpnd`i?xjqv=4(t`XY zMATufa!xXEx)s7KLt=ItgpC$RI%ElCef3bG2DaYqbIKhmq5F7qiM-SzE07rBRpc~? z?LNgJwKgh#xy2;~bc%{AY(Z!piP7SS|Bx!i5F#$>64_)%Yltz8E5Ik8ApZ@ehW+YY?o$ z$8!ypV>QL*(b?4(H(&9-bYq=AS($M1AOhY51Ee7QHn3R%#E4g-kYBZg?-fxItRC-1 z5rmPTMaQw1q!_ajoYiwAJ#6SLBdms!7+K@pIozvM->5FvUEAJyegoE Date: Wed, 13 Jul 2022 15:11:58 +0200 Subject: [PATCH 17/51] OP-3446 - store source file as a 'source' This will be stored in DB in version. Potentially it could be used to populate Ftrack Note. --- .../hosts/traypublisher/plugins/publish/collect_mov_batch.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py b/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py index 2a5e356684..c81d1f77a5 100644 --- a/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py +++ b/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py @@ -31,4 +31,6 @@ class CollectMovBatch( instance.data["representations"].append(repre) + instance.data["source"] = file_url + self.log.debug("instance.data {}".format(instance.data)) From c3649e0a571048cb0660656ce9dcf10176399b5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Thu, 14 Jul 2022 16:31:32 +0200 Subject: [PATCH 18/51] :bug: fix rfm api context for getting displays and multipart flag --- openpype/hosts/maya/api/lib_renderproducts.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/maya/api/lib_renderproducts.py b/openpype/hosts/maya/api/lib_renderproducts.py index 2d3bda5245..a8337ccf4d 100644 --- a/openpype/hosts/maya/api/lib_renderproducts.py +++ b/openpype/hosts/maya/api/lib_renderproducts.py @@ -1087,7 +1087,7 @@ class RenderProductsRenderman(ARenderProducts): "d_tiff": "tif" } - displays = get_displays()["displays"] + displays = get_displays(override_dst="render")["displays"] for name, display in displays.items(): enabled = display["params"]["enable"]["value"] if not enabled: @@ -1106,9 +1106,16 @@ class RenderProductsRenderman(ARenderProducts): display["driverNode"]["type"], "exr") for camera in cameras: - product = RenderProduct(productName=aov_name, - ext=extensions, - camera=camera) + # Create render product and set it as multipart only on + # display types supporting it. In all other cases, Renderman + # will create separate output per channel. + product = RenderProduct( + productName=aov_name, + ext=extensions, + camera=camera, + multipart=display["driverNode"]["type"] in ["d_openexr", "d_deepexr", "d_tiff"] # noqa + ) + products.append(product) return products From fbd239299f70105486db3276c218adfcccdf1e82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Thu, 14 Jul 2022 17:00:26 +0200 Subject: [PATCH 19/51] :recycle: comment on non-multipart code and raise exception --- openpype/hosts/maya/api/lib_renderproducts.py | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/maya/api/lib_renderproducts.py b/openpype/hosts/maya/api/lib_renderproducts.py index a8337ccf4d..0bc8682290 100644 --- a/openpype/hosts/maya/api/lib_renderproducts.py +++ b/openpype/hosts/maya/api/lib_renderproducts.py @@ -1109,12 +1109,28 @@ class RenderProductsRenderman(ARenderProducts): # Create render product and set it as multipart only on # display types supporting it. In all other cases, Renderman # will create separate output per channel. - product = RenderProduct( - productName=aov_name, - ext=extensions, - camera=camera, - multipart=display["driverNode"]["type"] in ["d_openexr", "d_deepexr", "d_tiff"] # noqa - ) + if display["driverNode"]["type"] in ["d_openexr", "d_deepexr", "d_tiff"]: # noqa + product = RenderProduct( + productName=aov_name, + ext=extensions, + camera=camera, + multipart=True + ) + else: + # this code should handle the case where no multipart + # capable format is selected. But since it involves + # shady logic to determine what channel become what + # lets not do that as all productions will use exr anyway. + """ + for channel in display['params']['displayChannels']['value']: # noqa + product = RenderProduct( + productName="{}_{}".format(aov_name, channel), + ext=extensions, + camera=camera, + multipart=False + ) + """ + raise UnsupportedImageFormatException("Only exr, deep exr and tiff formats are supported.") products.append(product) @@ -1208,3 +1224,7 @@ class UnsupportedRendererException(Exception): Raised when requesting data from unsupported renderer. """ + + +class UnsupportedImageFormatException(Exception): + """Custom exception to report unsupported output image format.""" From ef5b571ea6dbfae4df12a18f8412a4e90a88cf1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Thu, 14 Jul 2022 17:17:25 +0200 Subject: [PATCH 20/51] :dog: hound fix --- openpype/hosts/maya/api/lib_renderproducts.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/api/lib_renderproducts.py b/openpype/hosts/maya/api/lib_renderproducts.py index 0bc8682290..123b934428 100644 --- a/openpype/hosts/maya/api/lib_renderproducts.py +++ b/openpype/hosts/maya/api/lib_renderproducts.py @@ -1130,7 +1130,8 @@ class RenderProductsRenderman(ARenderProducts): multipart=False ) """ - raise UnsupportedImageFormatException("Only exr, deep exr and tiff formats are supported.") + raise UnsupportedImageFormatException( + "Only exr, deep exr and tiff formats are supported.") products.append(product) From a8c219211d5f2dddaf6b4dd31fd59d1137bbd0c1 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 15 Jul 2022 13:25:42 +0200 Subject: [PATCH 21/51] OP-3589 - copied ValidateFrameRange from SP SP will be removed in the future, copied this to TrayPublisher to keep functionality. --- .../publish/help/validate_frame_ranges.xml | 15 ++++ .../plugins/publish/validate_frame_ranges.py | 72 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 openpype/hosts/traypublisher/plugins/publish/help/validate_frame_ranges.xml create mode 100644 openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py diff --git a/openpype/hosts/traypublisher/plugins/publish/help/validate_frame_ranges.xml b/openpype/hosts/traypublisher/plugins/publish/help/validate_frame_ranges.xml new file mode 100644 index 0000000000..933df1c7c5 --- /dev/null +++ b/openpype/hosts/traypublisher/plugins/publish/help/validate_frame_ranges.xml @@ -0,0 +1,15 @@ + + + +Invalid frame range + +## Invalid frame range + +Expected duration or '{duration}' frames set in database, workfile contains only '{found}' frames. + +### How to repair? + +Modify configuration in the database or tweak frame range in the workfile. + + + \ No newline at end of file diff --git a/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py b/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py new file mode 100644 index 0000000000..89289fc6d4 --- /dev/null +++ b/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py @@ -0,0 +1,72 @@ +import re + +import pyblish.api + +import openpype.api +from openpype import lib +from openpype.pipeline import ( + PublishXmlValidationError, + OptionalPyblishPluginMixin +) + + +class ValidateFrameRange(OptionalPyblishPluginMixin, + pyblish.api.InstancePlugin): + """Validating frame range of rendered files against state in DB.""" + + label = "Validate Frame Range" + hosts = ["traypublisher"] + families = ["render"] + order = openpype.api.ValidateContentsOrder + + optional = True + # published data might be sequence (.mov, .mp4) in that counting files + # doesnt make sense + check_extensions = ["exr", "dpx", "jpg", "jpeg", "png", "tiff", "tga", + "gif", "svg"] + skip_timelines_check = [] # skip for specific task names (regex) + + def process(self, instance): + # Skip the instance if is not active by data on the instance + if not self.is_active(instance.data): + return + + if any(re.search(pattern, instance.data["task"]) + for pattern in self.skip_timelines_check): + self.log.info("Skipping for {} task".format(instance.data["task"])) + + asset_data = lib.get_asset(instance.data["asset"])["data"] + frame_start = asset_data["frameStart"] + frame_end = asset_data["frameEnd"] + handle_start = asset_data["handleStart"] + handle_end = asset_data["handleEnd"] + duration = (frame_end - frame_start + 1) + handle_start + handle_end + + repre = instance.data.get("representations", [None]) + if not repre: + self.log.info("No representations, skipping.") + return + + ext = repre[0]['ext'].replace(".", '') + + if not ext or ext.lower() not in self.check_extensions: + self.log.warning("Cannot check for extension {}".format(ext)) + return + + files = instance.data.get("representations", [None])[0]["files"] + if isinstance(files, str): + files = [files] + frames = len(files) + + msg = "Frame duration from DB:'{}' ". format(int(duration)) +\ + " doesn't match number of files:'{}'".format(frames) +\ + " Please change frame range for Asset or limit no. of files" + + formatting_data = {"duration": duration, + "found": frames} + if frames != duration: + raise PublishXmlValidationError(self, msg, + formatting_data=formatting_data) + + self.log.debug("Valid ranges expected '{}' - found '{}'". + format(int(duration), frames)) From 0111f4ae0f70b48e1098f8e28ed50ac969f1a8f3 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 15 Jul 2022 14:38:59 +0200 Subject: [PATCH 22/51] added option to launch openpype with interactive console --- openpype/cli.py | 16 +++++++++++++++- openpype/pype_commands.py | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/openpype/cli.py b/openpype/cli.py index 2aa4a46929..d6970f2509 100644 --- a/openpype/cli.py +++ b/openpype/cli.py @@ -2,7 +2,7 @@ """Package for handling pype command line arguments.""" import os import sys - +import code import click # import sys @@ -424,3 +424,17 @@ def pack_project(project, dirpath): def unpack_project(zipfile, root): """Create a package of project with all files and database dump.""" PypeCommands().unpack_project(zipfile, root) + + +@main.command() +def interactive(): + """Interative (Python like) console. + + Helpfull command not only for development to directly work with python + interpreter. + + Warning: + Executable 'openpype_gui' on windows won't work. + """ + + code.interact() diff --git a/openpype/pype_commands.py b/openpype/pype_commands.py index 90c582a319..124eacbe39 100644 --- a/openpype/pype_commands.py +++ b/openpype/pype_commands.py @@ -7,7 +7,7 @@ import time from openpype.lib import PypeLogger from openpype.api import get_app_environments_for_context -from openpype.lib.plugin_tools import parse_json, get_batch_asset_task_info +from openpype.lib.plugin_tools import get_batch_asset_task_info from openpype.lib.remote_publish import ( get_webpublish_conn, start_webpublish_log, From b60acdd6d77d488464ffdfad871b076926d94896 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 15 Jul 2022 14:45:32 +0200 Subject: [PATCH 23/51] added banner to interpreter --- openpype/cli.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/openpype/cli.py b/openpype/cli.py index d6970f2509..9a2dfaa141 100644 --- a/openpype/cli.py +++ b/openpype/cli.py @@ -437,4 +437,9 @@ def interactive(): Executable 'openpype_gui' on windows won't work. """ - code.interact() + from openpype.version import __version__ + + banner = "OpenPype {}\nPython {} on {}".format( + __version__, sys.version, sys.platform + ) + code.interact(banner) From a395a85b67065e34c445e2b522afedb8d0f6cf42 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 15 Jul 2022 15:07:11 +0200 Subject: [PATCH 24/51] OP-3446 - explicitly adding review Creator now should handle adding review on instance and on applicable representation tags. --- .../plugins/create/create_mov_batch.py | 15 +++++++++++++-- .../plugins/publish/collect_mov_batch.py | 17 +++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py b/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py index 20d3ecbd7c..67f8848e05 100644 --- a/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py +++ b/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py @@ -4,7 +4,7 @@ import re from openpype.client import get_assets, get_asset_by_name from openpype.hosts.traypublisher.api import pipeline -from openpype.lib import FileDef, get_subset_name_with_asset_doc +from openpype.lib import FileDef, BoolDef, get_subset_name_with_asset_doc from openpype.pipeline import ( CreatedInstance, CreatorError @@ -151,7 +151,13 @@ class BatchMovCreator(TrayPublishCreator): return task_name def get_instance_attr_defs(self): - return [] + return [ + BoolDef( + "add_review_family", + default=True, + label="Review" + ) + ] def get_pre_create_attr_defs(self): # Use same attributes as for instance attributes @@ -162,6 +168,11 @@ class BatchMovCreator(TrayPublishCreator): single_item=False, extensions=self.extensions, label="Filepath" + ), + BoolDef( + "add_review_family", + default=True, + label="Review" ) ] diff --git a/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py b/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py index c81d1f77a5..e4011d0003 100644 --- a/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py +++ b/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py @@ -2,12 +2,17 @@ import os import pyblish.api from openpype.pipeline import OpenPypePyblishPluginMixin +from openpype.lib import BoolDef class CollectMovBatch( pyblish.api.InstancePlugin, OpenPypePyblishPluginMixin ): - """Collect file url for batch mov and create representation.""" + """Collect file url for batch mov and create representation. + + Adds review on instance and to repre.tags based on value of toggle button + on creator. + """ label = "Collect Mov Batch Files" order = pyblish.api.CollectorOrder @@ -18,7 +23,9 @@ class CollectMovBatch( if not instance.data.get("creator_identifier") == "render_mov_batch": return - file_url = instance.data["creator_attributes"]["filepath"] + creator_attributes = instance.data["creator_attributes"] + + file_url = creator_attributes["filepath"] file_name = os.path.basename(file_url) _, ext = os.path.splitext(file_name) @@ -29,6 +36,12 @@ class CollectMovBatch( "stagingDir": os.path.dirname(file_url) } + if creator_attributes["add_review_family"]: + if not repre.get("tags"): + repre["tags"] = [] + repre["tags"].append("review") + instance.data["families"].append("review") + instance.data["representations"].append(repre) instance.data["source"] = file_url From a1b93b1d4812cd44dc20f8f69e5f6953d91e7d52 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 15 Jul 2022 15:08:16 +0200 Subject: [PATCH 25/51] OP-3446 - Hound --- .../hosts/traypublisher/plugins/publish/collect_mov_batch.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py b/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py index e4011d0003..99065d2408 100644 --- a/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py +++ b/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py @@ -2,7 +2,6 @@ import os import pyblish.api from openpype.pipeline import OpenPypePyblishPluginMixin -from openpype.lib import BoolDef class CollectMovBatch( From 1c71fe206d2a531fbd921fd49368a74a966e3426 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 15 Jul 2022 18:20:01 +0200 Subject: [PATCH 26/51] added interactive command to documentation --- website/docs/admin_openpype_commands.md | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/admin_openpype_commands.md b/website/docs/admin_openpype_commands.md index 53b4799d6e..53fc12410f 100644 --- a/website/docs/admin_openpype_commands.md +++ b/website/docs/admin_openpype_commands.md @@ -45,6 +45,7 @@ For more information [see here](admin_use.md#run-openpype). | publish | Pype takes JSON from provided path and use it to publish data in it. | [📑](#publish-arguments) | | extractenvironments | Extract environment variables for entered context to a json file. | [📑](#extractenvironments-arguments) | | run | Execute given python script within OpenPype environment. | [📑](#run-arguments) | +| interactive | Start python like interactive console session. | | | projectmanager | Launch Project Manager UI | [📑](#projectmanager-arguments) | | settings | Open Settings UI | [📑](#settings-arguments) | | standalonepublisher | Open Standalone Publisher UI | [📑](#standalonepublisher-arguments) | From 247db779fe416c663d0b8e4ae100284fe9977476 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 18 Jul 2022 10:56:08 +0200 Subject: [PATCH 27/51] Update openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- .../traypublisher/plugins/publish/validate_frame_ranges.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py b/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py index 89289fc6d4..bb6b906e8d 100644 --- a/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py +++ b/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py @@ -58,9 +58,10 @@ class ValidateFrameRange(OptionalPyblishPluginMixin, files = [files] frames = len(files) - msg = "Frame duration from DB:'{}' ". format(int(duration)) +\ - " doesn't match number of files:'{}'".format(frames) +\ - " Please change frame range for Asset or limit no. of files" + msg = ( + "Frame duration from DB:'{}' doesn't match number of files:'{}'" + " Please change frame range for Asset or limit no. of files" + ). format(int(duration), frames) formatting_data = {"duration": duration, "found": frames} From cdabfbe6f9d0ea90df1a44525bf0ae88a45c825d Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 18 Jul 2022 10:56:25 +0200 Subject: [PATCH 28/51] Update openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- .../traypublisher/plugins/publish/validate_frame_ranges.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py b/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py index bb6b906e8d..0d7081139d 100644 --- a/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py +++ b/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py @@ -35,7 +35,8 @@ class ValidateFrameRange(OptionalPyblishPluginMixin, for pattern in self.skip_timelines_check): self.log.info("Skipping for {} task".format(instance.data["task"])) - asset_data = lib.get_asset(instance.data["asset"])["data"] + asset_doc = instance.data["assetEntity"] + asset_data = asset_doc["data"] frame_start = asset_data["frameStart"] frame_end = asset_data["frameEnd"] handle_start = asset_data["handleStart"] From ef2284e507cd43db6b14518244333d10db1091b6 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 18 Jul 2022 10:57:01 +0200 Subject: [PATCH 29/51] Update openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- .../plugins/publish/validate_frame_ranges.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py b/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py index 0d7081139d..6d48e8352c 100644 --- a/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py +++ b/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py @@ -43,18 +43,19 @@ class ValidateFrameRange(OptionalPyblishPluginMixin, handle_end = asset_data["handleEnd"] duration = (frame_end - frame_start + 1) + handle_start + handle_end - repre = instance.data.get("representations", [None]) - if not repre: + repres = instance.data.get("representations") + if not repres: self.log.info("No representations, skipping.") return - - ext = repre[0]['ext'].replace(".", '') + + first_repre = repres[0] + ext = first_repre['ext'].replace(".", '') if not ext or ext.lower() not in self.check_extensions: self.log.warning("Cannot check for extension {}".format(ext)) return - files = instance.data.get("representations", [None])[0]["files"] + files = first_repre["files"] if isinstance(files, str): files = [files] frames = len(files) From 247eaf792bb21fd294bf95bb64423965834a4b00 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 18 Jul 2022 11:01:30 +0200 Subject: [PATCH 30/51] Check only if skip_timelines_check is filled --- .../traypublisher/plugins/publish/validate_frame_ranges.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py b/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py index 6d48e8352c..65b6128cbe 100644 --- a/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py +++ b/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py @@ -31,8 +31,9 @@ class ValidateFrameRange(OptionalPyblishPluginMixin, if not self.is_active(instance.data): return - if any(re.search(pattern, instance.data["task"]) - for pattern in self.skip_timelines_check): + if (self.skip_timelines_check and + any(re.search(pattern, instance.data["task"]) + for pattern in self.skip_timelines_check)): self.log.info("Skipping for {} task".format(instance.data["task"])) asset_doc = instance.data["assetEntity"] From e21338424ed92c4b59422f487de6de501d756c3c Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 18 Jul 2022 11:02:50 +0200 Subject: [PATCH 31/51] Hound --- .../traypublisher/plugins/publish/validate_frame_ranges.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py b/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py index 65b6128cbe..947624100a 100644 --- a/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py +++ b/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py @@ -3,7 +3,6 @@ import re import pyblish.api import openpype.api -from openpype import lib from openpype.pipeline import ( PublishXmlValidationError, OptionalPyblishPluginMixin @@ -48,7 +47,7 @@ class ValidateFrameRange(OptionalPyblishPluginMixin, if not repres: self.log.info("No representations, skipping.") return - + first_repre = repres[0] ext = first_repre['ext'].replace(".", '') From 4f6646d6c7b712e8ad6678a410da41772642e868 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 18 Jul 2022 11:11:08 +0200 Subject: [PATCH 32/51] Update openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- .../hosts/traypublisher/plugins/publish/collect_mov_batch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py b/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py index 99065d2408..d24659aa8b 100644 --- a/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py +++ b/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py @@ -19,7 +19,7 @@ class CollectMovBatch( hosts = ["traypublisher"] def process(self, instance): - if not instance.data.get("creator_identifier") == "render_mov_batch": + if instance.data.get("creator_identifier") != "render_mov_batch": return creator_attributes = instance.data["creator_attributes"] From ca2f554a1c4b167d444bbdde1c962f4f9bd7198d Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 18 Jul 2022 17:27:49 +0200 Subject: [PATCH 33/51] escape html chars from label in widgets --- openpype/tools/publisher/publish_report_viewer/model.py | 4 +++- openpype/tools/publisher/widgets/card_view_widgets.py | 3 ++- openpype/tools/publisher/widgets/list_view_widgets.py | 7 +++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/openpype/tools/publisher/publish_report_viewer/model.py b/openpype/tools/publisher/publish_report_viewer/model.py index a88129a358..bd03376c55 100644 --- a/openpype/tools/publisher/publish_report_viewer/model.py +++ b/openpype/tools/publisher/publish_report_viewer/model.py @@ -1,4 +1,5 @@ import uuid +import html from Qt import QtCore, QtGui import pyblish.api @@ -45,7 +46,8 @@ class InstancesModel(QtGui.QStandardItemModel): all_removed = True for instance_item in instance_items: item = QtGui.QStandardItem(instance_item.label) - item.setData(instance_item.label, ITEM_LABEL_ROLE) + instance_label = html.escape(instance_item.label) + item.setData(instance_label, ITEM_LABEL_ROLE) item.setData(instance_item.errored, ITEM_ERRORED_ROLE) item.setData(instance_item.id, ITEM_ID_ROLE) item.setData(instance_item.removed, INSTANCE_REMOVED_ROLE) diff --git a/openpype/tools/publisher/widgets/card_view_widgets.py b/openpype/tools/publisher/widgets/card_view_widgets.py index b6fcee7edb..5a6878ddca 100644 --- a/openpype/tools/publisher/widgets/card_view_widgets.py +++ b/openpype/tools/publisher/widgets/card_view_widgets.py @@ -22,6 +22,7 @@ Only one item can be selected at a time. import re import collections +import html from Qt import QtWidgets, QtCore @@ -303,7 +304,7 @@ class InstanceCardWidget(CardWidget): self._last_variant = variant self._last_subset_name = subset_name # Make `variant` bold - label = self.instance.label + label = html.escape(self.instance.label) found_parts = set(re.findall(variant, label, re.IGNORECASE)) if found_parts: for part in found_parts: diff --git a/openpype/tools/publisher/widgets/list_view_widgets.py b/openpype/tools/publisher/widgets/list_view_widgets.py index 3476ee487e..3e4fd5b72d 100644 --- a/openpype/tools/publisher/widgets/list_view_widgets.py +++ b/openpype/tools/publisher/widgets/list_view_widgets.py @@ -23,6 +23,7 @@ selection can be enabled disabled using checkbox or keyboard key presses: ``` """ import collections +import html from Qt import QtWidgets, QtCore, QtGui @@ -113,7 +114,9 @@ class InstanceListItemWidget(QtWidgets.QWidget): self.instance = instance - subset_name_label = QtWidgets.QLabel(instance.label, self) + instance_label = html.escape(instance.label) + + subset_name_label = QtWidgets.QLabel(instance_label, self) subset_name_label.setObjectName("ListViewSubsetName") active_checkbox = NiceCheckbox(parent=self) @@ -178,7 +181,7 @@ class InstanceListItemWidget(QtWidgets.QWidget): # Check subset name label = self.instance.label if label != self._instance_label_widget.text(): - self._instance_label_widget.setText(label) + self._instance_label_widget.setText(html.escape(label)) # Check active state self.set_active(self.instance["active"]) # Check valid states From ddf07d790886a54e21eb3af0358102bbfc693643 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 18 Jul 2022 17:30:02 +0200 Subject: [PATCH 34/51] handle cases when task is not set and subset name requires it --- .../plugins/create/create_mov_batch.py | 37 ++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py b/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py index 67f8848e05..840b0647f9 100644 --- a/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py +++ b/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py @@ -4,7 +4,12 @@ import re from openpype.client import get_assets, get_asset_by_name from openpype.hosts.traypublisher.api import pipeline -from openpype.lib import FileDef, BoolDef, get_subset_name_with_asset_doc +from openpype.lib import ( + FileDef, + BoolDef, + get_subset_name_with_asset_doc, + TaskNotSetError, +) from openpype.pipeline import ( CreatedInstance, CreatorError @@ -124,13 +129,27 @@ class BatchMovCreator(TrayPublishCreator): """Create subset name according to standard template process""" task_name = self._get_task_name(asset_doc) - subset_name = get_subset_name_with_asset_doc( - self.family, - variant, - task_name, - asset_doc, - project_name - ) + try: + subset_name = get_subset_name_with_asset_doc( + self.family, + variant, + task_name, + asset_doc, + project_name + ) + except TaskNotSetError: + # Create instance with fake task + # - instance will be marked as invalid so it can't be published + # but user have ability to change it + # NOTE: This expect that there is not task 'Undefined' on asset + task_name = "Undefined" + subset_name = get_subset_name_with_asset_doc( + self.family, + variant, + task_name, + asset_doc, + project_name + ) return subset_name, task_name @@ -178,7 +197,7 @@ class BatchMovCreator(TrayPublishCreator): def get_detail_description(self): return """# Publish batch of .mov to multiple assets. - + File names must then contain only asset name, or asset name + version. (eg. 'chair.mov', 'chair_v001.mov', not really safe `my_chair_v001.mov` """ From 508b3e7d8eccb554b5a6ed9f1660d611b780633d Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 19 Jul 2022 10:47:10 +0200 Subject: [PATCH 35/51] Update openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- .../hosts/traypublisher/plugins/publish/collect_mov_batch.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py b/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py index d24659aa8b..e6f33bc619 100644 --- a/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py +++ b/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py @@ -32,12 +32,11 @@ class CollectMovBatch( "name": ext[1:], "ext": ext[1:], "files": file_name, - "stagingDir": os.path.dirname(file_url) + "stagingDir": os.path.dirname(file_url), + "tags": [] } if creator_attributes["add_review_family"]: - if not repre.get("tags"): - repre["tags"] = [] repre["tags"].append("review") instance.data["families"].append("review") From fa10d36f589d1961f9dcb425129a0a4a69399b86 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 19 Jul 2022 10:47:43 +0200 Subject: [PATCH 36/51] Better creation of instance Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- .../hosts/traypublisher/plugins/create/create_mov_batch.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py b/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py index 840b0647f9..bbabd73415 100644 --- a/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py +++ b/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py @@ -64,10 +64,7 @@ class BatchMovCreator(TrayPublishCreator): # Create new instance new_instance = CreatedInstance(self.family, subset_name, instance_data, self) - # Host implementation of storing metadata about instance - pipeline.HostContext.add_instance(new_instance.data_to_store()) - # Add instance to current context - self._add_instance_to_context(new_instance) + self._store_new_instance(new_instance) def get_asset_doc_from_file_name(self, source_filename, project_name): """Try to parse out asset name from file name provided. From b4bd2542ff86dea9ce0a480ca6d1524900d6847f Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 19 Jul 2022 10:57:30 +0200 Subject: [PATCH 37/51] OP-3446 - renamed from mov to movie Workflow should handle not only .mov, but .mp4s or any movie format. --- ...eate_mov_batch.py => create_movie_batch.py} | 18 +++++++++++------- ...ect_mov_batch.py => collect_movie_batch.py} | 4 ++-- .../project_settings/traypublisher.json | 2 +- .../schema_project_traypublisher.json | 4 ++-- 4 files changed, 16 insertions(+), 12 deletions(-) rename openpype/hosts/traypublisher/plugins/create/{create_mov_batch.py => create_movie_batch.py} (94%) rename openpype/hosts/traypublisher/plugins/publish/{collect_mov_batch.py => collect_movie_batch.py} (97%) diff --git a/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py b/openpype/hosts/traypublisher/plugins/create/create_movie_batch.py similarity index 94% rename from openpype/hosts/traypublisher/plugins/create/create_mov_batch.py rename to openpype/hosts/traypublisher/plugins/create/create_movie_batch.py index bbabd73415..63b9b2ef28 100644 --- a/openpype/hosts/traypublisher/plugins/create/create_mov_batch.py +++ b/openpype/hosts/traypublisher/plugins/create/create_movie_batch.py @@ -18,21 +18,25 @@ from openpype.pipeline import ( from openpype.hosts.traypublisher.api.plugin import TrayPublishCreator -class BatchMovCreator(TrayPublishCreator): - """Creates instances from .mov file(s).""" - identifier = "render_mov_batch" - label = "Batch Mov" +class BatchMovieCreator(TrayPublishCreator): + """Creates instances from movie file(s). + + Intended for .mov files, but should work for any video file. + Doesn't handle image sequences though. + """ + identifier = "render_movie_batch" + label = "Batch Movies" family = "render" - description = "Publish batch of movs" + description = "Publish batch of video files" create_allow_context_change = False version_regex = re.compile(r"^(.+)_v([0-9]+)$") def __init__(self, project_settings, *args, **kwargs): - super(BatchMovCreator, self).__init__(project_settings, + super(BatchMovieCreator, self).__init__(project_settings, *args, **kwargs) creator_settings = ( - project_settings["traypublisher"]["BatchMovCreator"] + project_settings["traypublisher"]["BatchMovieCreator"] ) self.default_variants = creator_settings["default_variants"] self.default_tasks = creator_settings["default_tasks"] diff --git a/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py b/openpype/hosts/traypublisher/plugins/publish/collect_movie_batch.py similarity index 97% rename from openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py rename to openpype/hosts/traypublisher/plugins/publish/collect_movie_batch.py index e6f33bc619..45ccbd92d4 100644 --- a/openpype/hosts/traypublisher/plugins/publish/collect_mov_batch.py +++ b/openpype/hosts/traypublisher/plugins/publish/collect_movie_batch.py @@ -4,7 +4,7 @@ import pyblish.api from openpype.pipeline import OpenPypePyblishPluginMixin -class CollectMovBatch( +class CollectMovieBatch( pyblish.api.InstancePlugin, OpenPypePyblishPluginMixin ): """Collect file url for batch mov and create representation. @@ -19,7 +19,7 @@ class CollectMovBatch( hosts = ["traypublisher"] def process(self, instance): - if instance.data.get("creator_identifier") != "render_mov_batch": + if instance.data.get("creator_identifier") != "render_movie_batch": return creator_attributes = instance.data["creator_attributes"] diff --git a/openpype/settings/defaults/project_settings/traypublisher.json b/openpype/settings/defaults/project_settings/traypublisher.json index cbe58f49d6..8bf3e3b306 100644 --- a/openpype/settings/defaults/project_settings/traypublisher.json +++ b/openpype/settings/defaults/project_settings/traypublisher.json @@ -236,7 +236,7 @@ "extensions": [] } ], - "BatchMovCreator": { + "BatchMovieCreator": { "default_variants": ["Main"], "default_tasks": ["Compositing"], "extensions": [ diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json b/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json index 50ba246c97..e38aa64e04 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json @@ -87,8 +87,8 @@ { "type": "dict", "collapsible": true, - "key": "BatchMovCreator", - "label": "Batch Mov Creator", + "key": "BatchMovieCreator", + "label": "Batch Movie Creator", "use_label_wrap": true, "collapsible_key": true, "children": [ From 96be94c0c2b3aa2657bfe832b28904fbaec8ff53 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 19 Jul 2022 11:27:16 +0200 Subject: [PATCH 38/51] OP-3446 - added label to Settings Updated label for collector --- .../traypublisher/plugins/publish/collect_movie_batch.py | 4 ++-- .../projects_schema/schema_project_traypublisher.json | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/traypublisher/plugins/publish/collect_movie_batch.py b/openpype/hosts/traypublisher/plugins/publish/collect_movie_batch.py index 45ccbd92d4..f37e04d1c9 100644 --- a/openpype/hosts/traypublisher/plugins/publish/collect_movie_batch.py +++ b/openpype/hosts/traypublisher/plugins/publish/collect_movie_batch.py @@ -7,13 +7,13 @@ from openpype.pipeline import OpenPypePyblishPluginMixin class CollectMovieBatch( pyblish.api.InstancePlugin, OpenPypePyblishPluginMixin ): - """Collect file url for batch mov and create representation. + """Collect file url for batch movies and create representation. Adds review on instance and to repre.tags based on value of toggle button on creator. """ - label = "Collect Mov Batch Files" + label = "Collect Movie Batch Files" order = pyblish.api.CollectorOrder hosts = ["traypublisher"] diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json b/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json index e38aa64e04..8f0f864dc2 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json @@ -89,9 +89,12 @@ "collapsible": true, "key": "BatchMovieCreator", "label": "Batch Movie Creator", - "use_label_wrap": true, "collapsible_key": true, "children": [ + { + "type": "label", + "label": "Allows to publish multiple video files in one go.
Name of matching asset is parsed from file names ('asset.mov', 'asset_v001.mov', 'my_asset_to_publish.mov')" + }, { "type": "list", "key": "default_variants", From 505b42ace2a7e07bfff9cb191e0f5f873d6af181 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 19 Jul 2022 11:29:34 +0200 Subject: [PATCH 39/51] OP-3446 - Hound --- .../hosts/traypublisher/plugins/create/create_movie_batch.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openpype/hosts/traypublisher/plugins/create/create_movie_batch.py b/openpype/hosts/traypublisher/plugins/create/create_movie_batch.py index 63b9b2ef28..c5f0d6b75e 100644 --- a/openpype/hosts/traypublisher/plugins/create/create_movie_batch.py +++ b/openpype/hosts/traypublisher/plugins/create/create_movie_batch.py @@ -3,7 +3,6 @@ import os import re from openpype.client import get_assets, get_asset_by_name -from openpype.hosts.traypublisher.api import pipeline from openpype.lib import ( FileDef, BoolDef, @@ -34,7 +33,7 @@ class BatchMovieCreator(TrayPublishCreator): def __init__(self, project_settings, *args, **kwargs): super(BatchMovieCreator, self).__init__(project_settings, - *args, **kwargs) + *args, **kwargs) creator_settings = ( project_settings["traypublisher"]["BatchMovieCreator"] ) From 5940fd0937941ba0fea391be0889bfa86bedc806 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Wed, 20 Jul 2022 03:58:48 +0000 Subject: [PATCH 40/51] [Automated] Bump version --- CHANGELOG.md | 15 ++++++++------- openpype/version.py | 2 +- pyproject.toml | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95427e9ea9..e8da885473 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,23 +1,29 @@ # Changelog -## [3.12.2-nightly.1](https://github.com/pypeclub/OpenPype/tree/HEAD) +## [3.12.2-nightly.2](https://github.com/pypeclub/OpenPype/tree/HEAD) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.12.1...HEAD) **🚀 Enhancements** +- General: Interactive console in cli [\#3526](https://github.com/pypeclub/OpenPype/pull/3526) - Ftrack: Automatic daily review session creation can define trigger hour [\#3516](https://github.com/pypeclub/OpenPype/pull/3516) - Ftrack: add source into Note [\#3509](https://github.com/pypeclub/OpenPype/pull/3509) - Ftrack: Trigger custom ftrack topic of project structure creation [\#3506](https://github.com/pypeclub/OpenPype/pull/3506) - Settings UI: Add extract to file action on project view [\#3505](https://github.com/pypeclub/OpenPype/pull/3505) +- Add pack and unpack convenience scripts [\#3502](https://github.com/pypeclub/OpenPype/pull/3502) - General: Event system [\#3499](https://github.com/pypeclub/OpenPype/pull/3499) - NewPublisher: Keep plugins with mismatch target in report [\#3498](https://github.com/pypeclub/OpenPype/pull/3498) - Nuke: load clip with options from settings [\#3497](https://github.com/pypeclub/OpenPype/pull/3497) +- TrayPublisher: implemented render\_mov\_batch [\#3486](https://github.com/pypeclub/OpenPype/pull/3486) - Migrate basic families to the new Tray Publisher [\#3469](https://github.com/pypeclub/OpenPype/pull/3469) **🐛 Bug fixes** +- Additional fixes for powershell scripts [\#3525](https://github.com/pypeclub/OpenPype/pull/3525) +- Maya: Added wrapper around cmds.setAttr [\#3523](https://github.com/pypeclub/OpenPype/pull/3523) - General: Fix hash of centos oiio archive [\#3519](https://github.com/pypeclub/OpenPype/pull/3519) +- Maya: Renderman display output fix [\#3514](https://github.com/pypeclub/OpenPype/pull/3514) - TrayPublisher: Simple creation enhancements and fixes [\#3513](https://github.com/pypeclub/OpenPype/pull/3513) - NewPublisher: Publish attributes are properly collected [\#3510](https://github.com/pypeclub/OpenPype/pull/3510) - TrayPublisher: Make sure host name is filled [\#3504](https://github.com/pypeclub/OpenPype/pull/3504) @@ -25,6 +31,7 @@ **🔀 Refactored code** +- General: Client docstrings cleanup [\#3529](https://github.com/pypeclub/OpenPype/pull/3529) - TimersManager: Use query functions [\#3495](https://github.com/pypeclub/OpenPype/pull/3495) ## [3.12.1](https://github.com/pypeclub/OpenPype/tree/3.12.1) (2022-07-13) @@ -51,7 +58,6 @@ - Blender: Bugfix - Set fps properly on open [\#3426](https://github.com/pypeclub/OpenPype/pull/3426) - Hiero: Add custom scripts menu [\#3425](https://github.com/pypeclub/OpenPype/pull/3425) - Blender: pre pyside install for all platforms [\#3400](https://github.com/pypeclub/OpenPype/pull/3400) -- Maya: Add additional playblast options to review Extractor. [\#3384](https://github.com/pypeclub/OpenPype/pull/3384) **🐛 Bug fixes** @@ -71,7 +77,6 @@ - Maya: fix hashing in Python 3 for tile rendering [\#3447](https://github.com/pypeclub/OpenPype/pull/3447) - LogViewer: Escape html characters in log message [\#3443](https://github.com/pypeclub/OpenPype/pull/3443) - Nuke: Slate frame is integrated [\#3427](https://github.com/pypeclub/OpenPype/pull/3427) -- Maya: Camera extra data - additional fix for \#3304 [\#3386](https://github.com/pypeclub/OpenPype/pull/3386) **🔀 Refactored code** @@ -85,8 +90,6 @@ - General: Move publish plugin and publish render abstractions [\#3442](https://github.com/pypeclub/OpenPype/pull/3442) - General: Use Anatomy after move to pipeline [\#3436](https://github.com/pypeclub/OpenPype/pull/3436) - General: Anatomy moved to pipeline [\#3435](https://github.com/pypeclub/OpenPype/pull/3435) -- Fusion: Use client query functions [\#3380](https://github.com/pypeclub/OpenPype/pull/3380) -- Resolve: Use client query functions [\#3379](https://github.com/pypeclub/OpenPype/pull/3379) ## [3.12.0](https://github.com/pypeclub/OpenPype/tree/3.12.0) (2022-06-28) @@ -111,7 +114,6 @@ - Nuke: Collect representation files based on Write [\#3407](https://github.com/pypeclub/OpenPype/pull/3407) - General: Filter representations before integration start [\#3398](https://github.com/pypeclub/OpenPype/pull/3398) - Maya: look collector typo [\#3392](https://github.com/pypeclub/OpenPype/pull/3392) -- Maya: vray device aspect ratio fix [\#3381](https://github.com/pypeclub/OpenPype/pull/3381) **🔀 Refactored code** @@ -121,7 +123,6 @@ - Houdini: Use client query functions [\#3395](https://github.com/pypeclub/OpenPype/pull/3395) - Hiero: Use client query functions [\#3393](https://github.com/pypeclub/OpenPype/pull/3393) - Nuke: Use client query functions [\#3391](https://github.com/pypeclub/OpenPype/pull/3391) -- Maya: Use client query functions [\#3385](https://github.com/pypeclub/OpenPype/pull/3385) ## [3.11.1](https://github.com/pypeclub/OpenPype/tree/3.11.1) (2022-06-20) diff --git a/openpype/version.py b/openpype/version.py index e9206379e1..dd5ad97449 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.12.2-nightly.1" +__version__ = "3.12.2-nightly.2" diff --git a/pyproject.toml b/pyproject.toml index 19d65b50f9..9552242694 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.12.2-nightly.1" # OpenPype +version = "3.12.2-nightly.2" # OpenPype description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" From fca8030092e9e9fd165d2bdf2039b662be218499 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 20 Jul 2022 09:47:54 +0200 Subject: [PATCH 41/51] normalize path from get_workdir where needed --- .../hosts/flame/plugins/publish/integrate_batch_group.py | 6 ++++-- openpype/lib/applications.py | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/integrate_batch_group.py b/openpype/hosts/flame/plugins/publish/integrate_batch_group.py index da9553cc2a..032de99540 100644 --- a/openpype/hosts/flame/plugins/publish/integrate_batch_group.py +++ b/openpype/hosts/flame/plugins/publish/integrate_batch_group.py @@ -324,5 +324,7 @@ class IntegrateBatchGroup(pyblish.api.InstancePlugin): project_doc = instance.data["projectEntity"] asset_entity = instance.data["assetEntity"] - return get_workdir( - project_doc, asset_entity, task_data["name"], "flame") + workdir = get_workdir( + project_doc, asset_entity, task_data["name"], "flame" + ) + return os.path.normpath(workdir) diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index f46197e15f..dafc3b479b 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -1638,6 +1638,7 @@ def prepare_context_environments(data, env_group=None): "Error in anatomy.format: {}".format(str(exc)) ) + workdir = os.path.normpath(workdir) if not os.path.exists(workdir): log.debug( "Creating workdir folder: \"{}\"".format(workdir) From 37a02fe8e19e4faeaa2a63e3cced19efe5aa1fce Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 20 Jul 2022 09:48:21 +0200 Subject: [PATCH 42/51] 'get_workdir_with_workdir_data' returns 'TemplateResult' --- openpype/lib/avalon_context.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/openpype/lib/avalon_context.py b/openpype/lib/avalon_context.py index 76ed6cbbd3..605ebb0b99 100644 --- a/openpype/lib/avalon_context.py +++ b/openpype/lib/avalon_context.py @@ -582,10 +582,7 @@ def get_workdir_with_workdir_data( anatomy_filled = anatomy.format(workdir_data) # Output is TemplateResult object which contain useful data - path = anatomy_filled[template_key]["folder"] - if path: - path = os.path.normpath(path) - return path + return anatomy_filled[template_key]["folder"] def get_workdir( From afd26a82e376a6445177d63d7769394c22b5efa6 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 20 Jul 2022 09:48:42 +0200 Subject: [PATCH 43/51] pass anatomy to 'get_workdir' in flame integrator --- openpype/hosts/flame/plugins/publish/integrate_batch_group.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/flame/plugins/publish/integrate_batch_group.py b/openpype/hosts/flame/plugins/publish/integrate_batch_group.py index 032de99540..bf6e81523d 100644 --- a/openpype/hosts/flame/plugins/publish/integrate_batch_group.py +++ b/openpype/hosts/flame/plugins/publish/integrate_batch_group.py @@ -323,8 +323,9 @@ class IntegrateBatchGroup(pyblish.api.InstancePlugin): def _get_shot_task_dir_path(self, instance, task_data): project_doc = instance.data["projectEntity"] asset_entity = instance.data["assetEntity"] + anatomy = instance.context.data["anatomy"] workdir = get_workdir( - project_doc, asset_entity, task_data["name"], "flame" + project_doc, asset_entity, task_data["name"], "flame", anatomy ) return os.path.normpath(workdir) From 5963066a7e1ba2849092215697470e7e0ae734bd Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 20 Jul 2022 10:11:56 +0200 Subject: [PATCH 44/51] TemplateResult has 'normalized' method --- openpype/lib/path_templates.py | 13 +++++++++++++ openpype/pipeline/anatomy.py | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/openpype/lib/path_templates.py b/openpype/lib/path_templates.py index 5c40aa4549..c1282016ef 100644 --- a/openpype/lib/path_templates.py +++ b/openpype/lib/path_templates.py @@ -409,6 +409,19 @@ class TemplateResult(str): self.invalid_types ) + def normalized(self): + """Convert to normalized path.""" + + cls = self.__class__ + return cls( + os.path.normpath(self), + self.template, + self.solved, + self.used_values, + self.missing_keys, + self.invalid_types + ) + class TemplatesResultDict(dict): """Holds and wrap TemplateResults for easy bug report.""" diff --git a/openpype/pipeline/anatomy.py b/openpype/pipeline/anatomy.py index 73081f18fb..08db4749b3 100644 --- a/openpype/pipeline/anatomy.py +++ b/openpype/pipeline/anatomy.py @@ -380,6 +380,19 @@ class AnatomyTemplateResult(TemplateResult): ) return self.__class__(tmp, self.rootless) + def normalized(self): + """Convert to normalized path.""" + + tmp = TemplateResult( + os.path.normpath(self), + self.template, + self.solved, + self.used_values, + self.missing_keys, + self.invalid_types + ) + return self.__class__(tmp, self.rootless) + class AnatomyTemplates(TemplatesDict): inner_key_pattern = re.compile(r"(\{@.*?[^{}0]*\})") From ab34b6f1cf1b1e56b770dcac4191ca69c3a58a5b Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 20 Jul 2022 10:12:56 +0200 Subject: [PATCH 45/51] use normalized 'TemplateResult' output in 'get_workdir_with_workdir_data' --- .../hosts/flame/plugins/publish/integrate_batch_group.py | 3 +-- openpype/lib/applications.py | 1 - openpype/lib/avalon_context.py | 5 ++++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/integrate_batch_group.py b/openpype/hosts/flame/plugins/publish/integrate_batch_group.py index bf6e81523d..b59107f155 100644 --- a/openpype/hosts/flame/plugins/publish/integrate_batch_group.py +++ b/openpype/hosts/flame/plugins/publish/integrate_batch_group.py @@ -325,7 +325,6 @@ class IntegrateBatchGroup(pyblish.api.InstancePlugin): asset_entity = instance.data["assetEntity"] anatomy = instance.context.data["anatomy"] - workdir = get_workdir( + return get_workdir( project_doc, asset_entity, task_data["name"], "flame", anatomy ) - return os.path.normpath(workdir) diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index dafc3b479b..f46197e15f 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -1638,7 +1638,6 @@ def prepare_context_environments(data, env_group=None): "Error in anatomy.format: {}".format(str(exc)) ) - workdir = os.path.normpath(workdir) if not os.path.exists(workdir): log.debug( "Creating workdir folder: \"{}\"".format(workdir) diff --git a/openpype/lib/avalon_context.py b/openpype/lib/avalon_context.py index 605ebb0b99..2944b2506e 100644 --- a/openpype/lib/avalon_context.py +++ b/openpype/lib/avalon_context.py @@ -582,7 +582,10 @@ def get_workdir_with_workdir_data( anatomy_filled = anatomy.format(workdir_data) # Output is TemplateResult object which contain useful data - return anatomy_filled[template_key]["folder"] + output = anatomy_filled[template_key]["folder"] + if output: + return output.normalized() + return output def get_workdir( From 6ed18c6250e083a827be395cfc9746ffe7bdd2fa Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 20 Jul 2022 13:13:23 +0200 Subject: [PATCH 46/51] stop context timer when context is set --- openpype/tools/workfiles/window.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/tools/workfiles/window.py b/openpype/tools/workfiles/window.py index c1efe026f2..f5edff2fa5 100644 --- a/openpype/tools/workfiles/window.py +++ b/openpype/tools/workfiles/window.py @@ -331,6 +331,7 @@ class Window(QtWidgets.QMainWindow): if self.assets_widget.refreshing: return + self._set_context_timer.stop() self._context_to_set, context = None, self._context_to_set if "asset" in context: asset_doc = get_asset_by_name( From 58611f89bda27a745defb77a54fe27ff3555ffb7 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 20 Jul 2022 13:15:12 +0200 Subject: [PATCH 47/51] global function 'show_workfiles' just pass args and kwargs --- openpype/tools/utils/host_tools.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/tools/utils/host_tools.py b/openpype/tools/utils/host_tools.py index ae23e4d089..41c4478d57 100644 --- a/openpype/tools/utils/host_tools.py +++ b/openpype/tools/utils/host_tools.py @@ -395,9 +395,9 @@ def show_tool_by_name(tool_name, parent=None, *args, **kwargs): _SingletonPoint.show_tool_by_name(tool_name, parent, *args, **kwargs) -def show_workfiles(parent=None, use_context=None, save=None): +def show_workfiles(*args, **kwargs): _SingletonPoint.show_tool_by_name( - "workfiles", parent, use_context=use_context, save=save + "workfiles", *args, **kwargs ) From 8e4627b44dd6e1a667b742415c6d00946dba3220 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 20 Jul 2022 13:15:37 +0200 Subject: [PATCH 48/51] set icon of workfiles tool --- openpype/tools/workfiles/window.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openpype/tools/workfiles/window.py b/openpype/tools/workfiles/window.py index f5edff2fa5..e86b716765 100644 --- a/openpype/tools/workfiles/window.py +++ b/openpype/tools/workfiles/window.py @@ -1,6 +1,6 @@ import os import datetime -from Qt import QtCore, QtWidgets +from Qt import QtCore, QtWidgets, QtGui from openpype.client import ( get_asset_by_id, @@ -8,6 +8,7 @@ from openpype.client import ( get_workfile_info, ) from openpype import style +from openpype import resources from openpype.lib import ( create_workfile_doc, save_workfile_data_to_doc, @@ -153,6 +154,8 @@ class Window(QtWidgets.QMainWindow): if not parent: window_flags |= QtCore.Qt.WindowStaysOnTopHint self.setWindowFlags(window_flags) + icon = QtGui.QIcon(resources.get_openpype_icon_filepath()) + self.setWindowIcon(icon) # Create pages widget and set it as central widget pages_widget = QtWidgets.QStackedWidget(self) From 55ff302d21a49b13281972129a944adcb998bf89 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 20 Jul 2022 13:15:58 +0200 Subject: [PATCH 49/51] changed workfiles window to QWidget --- openpype/tools/workfiles/window.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/openpype/tools/workfiles/window.py b/openpype/tools/workfiles/window.py index e86b716765..588daf069f 100644 --- a/openpype/tools/workfiles/window.py +++ b/openpype/tools/workfiles/window.py @@ -143,23 +143,19 @@ class SidePanelWidget(QtWidgets.QWidget): return self._workfile_doc, data -class Window(QtWidgets.QMainWindow): +class Window(QtWidgets.QWidget): """Work Files Window""" title = "Work Files" def __init__(self, parent=None): super(Window, self).__init__(parent=parent) self.setWindowTitle(self.title) - window_flags = QtCore.Qt.Window | QtCore.Qt.WindowCloseButtonHint - if not parent: - window_flags |= QtCore.Qt.WindowStaysOnTopHint - self.setWindowFlags(window_flags) icon = QtGui.QIcon(resources.get_openpype_icon_filepath()) self.setWindowIcon(icon) + self.setWindowFlags(self.windowFlags() | QtCore.Qt.Window) # Create pages widget and set it as central widget pages_widget = QtWidgets.QStackedWidget(self) - self.setCentralWidget(pages_widget) home_page_widget = QtWidgets.QWidget(pages_widget) home_body_widget = QtWidgets.QWidget(home_page_widget) @@ -194,6 +190,9 @@ class Window(QtWidgets.QMainWindow): # the files widget has a filter field which tasks does not. tasks_widget.setContentsMargins(0, 32, 0, 0) + main_layout = QtWidgets.QHBoxLayout(self) + main_layout.addWidget(pages_widget, 1) + # Set context after asset widget is refreshed # - to do so it is necessary to wait until refresh is done set_context_timer = QtCore.QTimer() From 3fac738361abb9446424fcb244d9768c2706f070 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 20 Jul 2022 13:16:15 +0200 Subject: [PATCH 50/51] show workfile just calls ensure visible on workfiles tool --- openpype/tools/utils/host_tools.py | 25 +++-------------- openpype/tools/workfiles/window.py | 43 ++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/openpype/tools/utils/host_tools.py b/openpype/tools/utils/host_tools.py index 41c4478d57..52d15a59f7 100644 --- a/openpype/tools/utils/host_tools.py +++ b/openpype/tools/utils/host_tools.py @@ -60,31 +60,14 @@ class HostToolsHelper: return self._workfiles_tool - def show_workfiles(self, parent=None, use_context=None, save=None): + def show_workfiles( + self, parent=None, use_context=None, save=None, on_top=None + ): """Workfiles tool for changing context and saving workfiles.""" - if use_context is None: - use_context = True - - if save is None: - save = True with qt_app_context(): workfiles_tool = self.get_workfiles_tool(parent) - workfiles_tool.set_save_enabled(save) - - if not workfiles_tool.isVisible(): - workfiles_tool.show() - - if use_context: - context = { - "asset": legacy_io.Session["AVALON_ASSET"], - "task": legacy_io.Session["AVALON_TASK"] - } - workfiles_tool.set_context(context) - - # Pull window to the front. - workfiles_tool.raise_() - workfiles_tool.activateWindow() + workfiles_tool.ensure_visible(use_context, save, on_top) def get_loader_tool(self, parent): """Create, cache and return loader tool window.""" diff --git a/openpype/tools/workfiles/window.py b/openpype/tools/workfiles/window.py index 588daf069f..0b0d67e589 100644 --- a/openpype/tools/workfiles/window.py +++ b/openpype/tools/workfiles/window.py @@ -229,6 +229,49 @@ class Window(QtWidgets.QWidget): self._first_show = True self._context_to_set = None + def ensure_visible( + self, use_context=None, save=None, on_top=None + ): + if save is None: + save = True + + self.set_save_enabled(save) + + if self.isVisible(): + use_context = False + elif use_context is None: + use_context = True + + if on_top is None and self._first_show: + on_top = self.parent() is None + + window_flags = self.windowFlags() + new_window_flags = window_flags + if on_top is True: + new_window_flags = window_flags | QtCore.Qt.WindowStaysOnTopHint + elif on_top is False: + new_window_flags = window_flags & ~QtCore.Qt.WindowStaysOnTopHint + + if new_window_flags != window_flags: + # Note this is not propagated after initialization of widget in + # some Qt builds + self.setWindowFlags(new_window_flags) + self.show() + + elif not self.isVisible(): + self.show() + + if use_context is None or use_context is True: + context = { + "asset": legacy_io.Session["AVALON_ASSET"], + "task": legacy_io.Session["AVALON_TASK"] + } + self.set_context(context) + + # Pull window to the front. + self.raise_() + self.activateWindow() + @property def project_name(self): return legacy_io.Session["AVALON_PROJECT"] From b128e98c8f6269a779ec87a66d35cf8b4d8bf6d1 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 20 Jul 2022 13:16:57 +0200 Subject: [PATCH 51/51] nuke does not pass parent widget for workfiles tool and tell it to change on top flag --- openpype/hosts/nuke/api/lib.py | 10 ++++++---- openpype/hosts/nuke/api/pipeline.py | 10 +++++++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 0929415c00..9b24c9fb38 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -2440,10 +2440,12 @@ def _launch_workfile_app(): if starting_up or closing_down: return - from .pipeline import get_main_window - - main_window = get_main_window() - host_tools.show_workfiles(parent=main_window) + # Make sure on top is enabled on first show so the window is not hidden + # under main nuke window + # - this happened on Centos 7 and it is because the focus of nuke + # changes to the main window after showing because of initialization + # which moves workfiles tool under it + host_tools.show_workfiles(parent=None, on_top=True) def process_workfile_builder(): diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 2e3621ba8f..0afc56d2f7 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -142,6 +142,14 @@ def uninstall(): _uninstall_menu() +def _show_workfiles(): + # Make sure parent is not set + # - this makes Workfiles tool as separated window which + # avoid issues with reopening + # - it is possible to explicitly change on top flag of the tool + host_tools.show_workfiles(parent=None, on_top=False) + + def _install_menu(): # uninstall original avalon menu main_window = get_main_window() @@ -158,7 +166,7 @@ def _install_menu(): menu.addSeparator() menu.addCommand( "Work Files...", - lambda: host_tools.show_workfiles(parent=main_window) + _show_workfiles ) menu.addSeparator()