From 018a48b1fbc0f8f1a2600ea0976744d9c659046a Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 30 Mar 2022 16:20:21 +0200 Subject: [PATCH 01/58] OP-2011 - cleanup of unnecessary long query from Setting --- .../plugins/publish/submit_maya_deadline.py | 35 ++++--------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py index 15a6f8d828..31a7c2f176 100644 --- a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py @@ -255,6 +255,8 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): tile_assembler_plugin = "OpenPypeTileAssembler" asset_dependencies = False limit_groups = [] + jobInfo = None + pluginInfo = None group = "none" def process(self, instance): @@ -272,37 +274,12 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): self.deadline_url = instance.data.get("deadlineUrl") assert self.deadline_url, "Requires Deadline Webservice URL" - self._job_info = ( - context.data["project_settings"].get( - "deadline", {}).get( - "publish", {}).get( - "MayaSubmitDeadline", {}).get( - "jobInfo", {}) - ) + # just using existing names from Setting + self._job_info = self.jobInfo - self._plugin_info = ( - context.data["project_settings"].get( - "deadline", {}).get( - "publish", {}).get( - "MayaSubmitDeadline", {}).get( - "pluginInfo", {}) - ) + self._plugin_info = self.pluginInfo - self.limit_groups = ( - context.data["project_settings"].get( - "deadline", {}).get( - "publish", {}).get( - "MayaSubmitDeadline", {}).get( - "limit", []) - ) - - self.group = ( - context.data["project_settings"].get( - "deadline", {}).get( - "publish", {}).get( - "MayaSubmitDeadline", {}).get( - "group", "none") - ) + self.limit_groups = self.limit context = instance.context workspace = context.data["workspaceDir"] From eb95e11607483dd5f7b106c4701847f56e36a4f2 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 31 Mar 2022 18:57:08 +0200 Subject: [PATCH 02/58] OP-2011 - added pulling priority for DL from Settings Default value is from Settings, artist can modify it. --- openpype/hosts/maya/plugins/create/create_render.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openpype/hosts/maya/plugins/create/create_render.py b/openpype/hosts/maya/plugins/create/create_render.py index 9002ae3876..7ac739b227 100644 --- a/openpype/hosts/maya/plugins/create/create_render.py +++ b/openpype/hosts/maya/plugins/create/create_render.py @@ -294,6 +294,12 @@ class CreateRender(plugin.Creator): deadline_url = next(iter(self.deadline_servers.values())) pool_names = self._get_deadline_pools(deadline_url) + priority = self._project_settings.get( + "deadline", {}).get( + "publish", {}).get( + "MayaSubmitDeadline", {}).get( + "priority", 50) + self.data["priority"] = priority if muster_enabled: self.log.info(">>> Loading Muster credentials ...") From 79de61cda50d5e1f6c3897d1a31d780fecbea8b1 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 31 Mar 2022 19:01:59 +0200 Subject: [PATCH 03/58] OP-2011 - added separate tile_priority field --- .../hosts/maya/plugins/create/create_render.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/maya/plugins/create/create_render.py b/openpype/hosts/maya/plugins/create/create_render.py index 7ac739b227..4f0a394f85 100644 --- a/openpype/hosts/maya/plugins/create/create_render.py +++ b/openpype/hosts/maya/plugins/create/create_render.py @@ -252,6 +252,7 @@ class CreateRender(plugin.Creator): """Create instance settings.""" # get pools pool_names = [] + default_priority = 50 self.server_aliases = list(self.deadline_servers.keys()) self.data["deadlineServers"] = self.server_aliases @@ -260,7 +261,8 @@ class CreateRender(plugin.Creator): self.data["extendFrames"] = False self.data["overrideExistingFrame"] = True # self.data["useLegacyRenderLayers"] = True - self.data["priority"] = 50 + self.data["priority"] = default_priority + self.data["tile_priority"] = default_priority self.data["framesPerTask"] = 1 self.data["whitelist"] = False self.data["machineList"] = "" @@ -294,13 +296,17 @@ class CreateRender(plugin.Creator): deadline_url = next(iter(self.deadline_servers.values())) pool_names = self._get_deadline_pools(deadline_url) - priority = self._project_settings.get( + maya_submit_dl = self._project_settings.get( "deadline", {}).get( "publish", {}).get( - "MayaSubmitDeadline", {}).get( - "priority", 50) + "MayaSubmitDeadline", {}) + priority = maya_submit_dl.get("priority", default_priority) self.data["priority"] = priority + tile_priority = maya_submit_dl.get("tile_priority", + default_priority) + self.data["tile_priority"] = tile_priority + if muster_enabled: self.log.info(">>> Loading Muster credentials ...") self._load_credentials() From c345e4aa27b615ad529d5b4a9e20d503a0b27cb8 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 31 Mar 2022 19:02:56 +0200 Subject: [PATCH 04/58] OP-2011 - added separate tile_priority to submit to DL --- .../deadline/plugins/publish/submit_maya_deadline.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py index 31a7c2f176..2d2d70758f 100644 --- a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py @@ -254,6 +254,8 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): use_published = True tile_assembler_plugin = "OpenPypeTileAssembler" asset_dependencies = False + priority = 50 + tile_priority = 50 limit_groups = [] jobInfo = None pluginInfo = None @@ -442,7 +444,7 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): self.payload_skeleton["JobInfo"]["UserName"] = deadline_user # Set job priority self.payload_skeleton["JobInfo"]["Priority"] = \ - self._instance.data.get("priority", 50) + self._instance.data.get("priority", self.priority) if self.group != "none" and self.group: self.payload_skeleton["JobInfo"]["Group"] = self.group @@ -612,7 +614,7 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): } assembly_payload["JobInfo"].update(output_filenames) assembly_payload["JobInfo"]["Priority"] = self._instance.data.get( - "priority", 50) + "tile_priority", self.tile_priority) assembly_payload["JobInfo"]["UserName"] = deadline_user frame_payloads = [] From 6aa23b5c3946756921d54b7fd52554ad332902c1 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 31 Mar 2022 19:06:15 +0200 Subject: [PATCH 05/58] OP-2011 - added separate tile_priority to Settings --- .../defaults/project_settings/deadline.json | 56 ++++++++++--------- .../schema_project_deadline.json | 12 ++++ 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/openpype/settings/defaults/project_settings/deadline.json b/openpype/settings/defaults/project_settings/deadline.json index 5bb0a4022e..053c50ce8b 100644 --- a/openpype/settings/defaults/project_settings/deadline.json +++ b/openpype/settings/defaults/project_settings/deadline.json @@ -15,33 +15,6 @@ "deadline" ] }, - "ProcessSubmittedJobOnFarm": { - "enabled": true, - "deadline_department": "", - "deadline_pool": "", - "deadline_group": "", - "deadline_chunk_size": 1, - "deadline_priority": 50, - "publishing_script": "", - "skip_integration_repre_list": [], - "aov_filter": { - "maya": [ - ".+(?:\\.|_)([Bb]eauty)(?:\\.|_).*" - ], - "nuke": [ - ".*" - ], - "aftereffects": [ - ".*" - ], - "celaction": [ - ".*" - ], - "harmony": [ - ".*" - ] - } - }, "MayaSubmitDeadline": { "enabled": true, "optional": false, @@ -49,6 +22,8 @@ "tile_assembler_plugin": "OpenPypeTileAssembler", "use_published": true, "asset_dependencies": true, + "priority": 50, + "tile_priority": 50, "group": "none", "limit": [], "jobInfo": {}, @@ -95,6 +70,33 @@ "group": "", "department": "", "multiprocess": true + }, + "ProcessSubmittedJobOnFarm": { + "enabled": true, + "deadline_department": "", + "deadline_pool": "", + "deadline_group": "", + "deadline_chunk_size": 1, + "deadline_priority": 40, + "publishing_script": "", + "skip_integration_repre_list": [], + "aov_filter": { + "maya": [ + ".+(?:\\.|_)([Bb]eauty)(?:\\.|_).*" + ], + "nuke": [ + ".*" + ], + "aftereffects": [ + ".*" + ], + "celaction": [ + ".*" + ], + "harmony": [ + ".*" + ] + } } } } \ No newline at end of file diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json b/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json index e6097a2b14..0348543c81 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json @@ -117,6 +117,18 @@ "key": "asset_dependencies", "label": "Use Asset dependencies" }, + { + "type": "number", + "key": "priority", + "label": "Priority", + "default": 50 + }, + { + "type": "number", + "key": "tile_priority", + "label": "Tile Assembler Priority", + "default": 50 + }, { "type": "text", "key": "group", From 700184cfdc2f3dbabb3b49bbc1d9464fd3939a25 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 31 Mar 2022 19:44:23 +0200 Subject: [PATCH 06/58] OP-2011 - added priority to publish job --- .../deadline/plugins/publish/submit_publish_job.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_publish_job.py b/openpype/modules/deadline/plugins/publish/submit_publish_job.py index fad4d14ea0..29a276d3b3 100644 --- a/openpype/modules/deadline/plugins/publish/submit_publish_job.py +++ b/openpype/modules/deadline/plugins/publish/submit_publish_job.py @@ -916,12 +916,6 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): # User is deadline user render_job["Props"]["User"] = context.data.get( "deadlineUser", getpass.getuser()) - # Priority is now not handled at all - - if self.deadline_priority: - render_job["Props"]["Pri"] = self.deadline_priority - else: - render_job["Props"]["Pri"] = instance.data.get("priority") render_job["Props"]["Env"] = { "FTRACK_API_USER": os.environ.get("FTRACK_API_USER"), @@ -937,6 +931,11 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): self.deadline_url = instance.data.get("deadlineUrl") assert self.deadline_url, "Requires Deadline Webservice URL" + if self.deadline_priority: + render_job["Props"]["Pri"] = self.deadline_priority + else: + render_job["Props"]["Pri"] = instance.data.get("priority") + self._submit_deadline_post_job(instance, render_job, instances) # publish job file From 1947ccc0f2b8aace0b02e1f8c5581fd35913b673 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 1 Apr 2022 16:47:40 +0200 Subject: [PATCH 07/58] OP-2011 - cleaned up settings --- openpype/settings/defaults/project_settings/deadline.json | 2 +- .../schemas/projects_schema/schema_project_deadline.json | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/openpype/settings/defaults/project_settings/deadline.json b/openpype/settings/defaults/project_settings/deadline.json index 053c50ce8b..7311b64046 100644 --- a/openpype/settings/defaults/project_settings/deadline.json +++ b/openpype/settings/defaults/project_settings/deadline.json @@ -77,7 +77,7 @@ "deadline_pool": "", "deadline_group": "", "deadline_chunk_size": 1, - "deadline_priority": 40, + "deadline_priority": 50, "publishing_script": "", "skip_integration_repre_list": [], "aov_filter": { diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json b/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json index 0348543c81..e730c42a8a 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json @@ -120,14 +120,12 @@ { "type": "number", "key": "priority", - "label": "Priority", - "default": 50 + "label": "Priority" }, { "type": "number", "key": "tile_priority", "label": "Tile Assembler Priority", - "default": 50 }, { "type": "text", From ba622d570e5fef83ce0edb460558889fe307e058 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 1 Apr 2022 16:53:24 +0200 Subject: [PATCH 08/58] OP-2011 - changed back default data type --- .../modules/deadline/plugins/publish/submit_maya_deadline.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py index 2d2d70758f..34147712bc 100644 --- a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py @@ -257,8 +257,8 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): priority = 50 tile_priority = 50 limit_groups = [] - jobInfo = None - pluginInfo = None + jobInfo = {} + pluginInfo = {} group = "none" def process(self, instance): From 087c3e5e5ceb4de4d871b6aa5ffd8d0214399cfa Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 1 Apr 2022 16:59:24 +0200 Subject: [PATCH 09/58] OP-2011 - fix typo --- .../schemas/projects_schema/schema_project_deadline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json b/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json index e730c42a8a..b54d44d659 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json @@ -125,7 +125,7 @@ { "type": "number", "key": "tile_priority", - "label": "Tile Assembler Priority", + "label": "Tile Assembler Priority" }, { "type": "text", From 4783737bf9c64dcd6527ea24eb3efbc74ea38e84 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 1 Apr 2022 17:13:58 +0200 Subject: [PATCH 10/58] OP-2011 - refactored priority --- .../deadline/plugins/publish/submit_publish_job.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_publish_job.py b/openpype/modules/deadline/plugins/publish/submit_publish_job.py index 29a276d3b3..542c91b676 100644 --- a/openpype/modules/deadline/plugins/publish/submit_publish_job.py +++ b/openpype/modules/deadline/plugins/publish/submit_publish_job.py @@ -235,6 +235,8 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): if mongo_url: environment["OPENPYPE_MONGO"] = mongo_url + priority = self.deadline_priority or instance.data.get("priority") + args = [ "--headless", 'publish', @@ -254,7 +256,7 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): "Department": self.deadline_department, "ChunkSize": self.deadline_chunk_size, - "Priority": job["Props"]["Pri"], + "Priority": priority, "Group": self.deadline_group, "Pool": self.deadline_pool, @@ -931,11 +933,6 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): self.deadline_url = instance.data.get("deadlineUrl") assert self.deadline_url, "Requires Deadline Webservice URL" - if self.deadline_priority: - render_job["Props"]["Pri"] = self.deadline_priority - else: - render_job["Props"]["Pri"] = instance.data.get("priority") - self._submit_deadline_post_job(instance, render_job, instances) # publish job file From 26de072f8760e76ee46e864f57578708be20fd43 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 1 Apr 2022 17:42:08 +0200 Subject: [PATCH 11/58] OP-2011 - provide safer default --- openpype/modules/deadline/plugins/publish/submit_publish_job.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_publish_job.py b/openpype/modules/deadline/plugins/publish/submit_publish_job.py index 542c91b676..03adc7b168 100644 --- a/openpype/modules/deadline/plugins/publish/submit_publish_job.py +++ b/openpype/modules/deadline/plugins/publish/submit_publish_job.py @@ -235,7 +235,7 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): if mongo_url: environment["OPENPYPE_MONGO"] = mongo_url - priority = self.deadline_priority or instance.data.get("priority") + priority = self.deadline_priority or instance.data.get("priority", 50) args = [ "--headless", From 986c3287494edb194724c402ae50615c38c07a42 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Sat, 2 Apr 2022 12:04:25 +0200 Subject: [PATCH 12/58] Resolve environment variable in credential path with accre --- openpype/modules/sync_server/providers/gdrive.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/openpype/modules/sync_server/providers/gdrive.py b/openpype/modules/sync_server/providers/gdrive.py index 0b586613b5..6a8d2b3422 100644 --- a/openpype/modules/sync_server/providers/gdrive.py +++ b/openpype/modules/sync_server/providers/gdrive.py @@ -3,7 +3,7 @@ import os.path import time import sys import six -import platform +import acre from openpype.api import Logger from openpype.api import get_system_settings @@ -73,8 +73,13 @@ class GDriveHandler(AbstractProvider): format(site_name)) return - cred_path = self.presets.get("credentials_url", {}).\ - get(platform.system().lower()) or '' + cred_data = { + 'cred_path': self.presets.get("credentials_url", {}) + } + cred_data = acre.parse(cred_data) + cred_data = acre.merge(cred_data, current_env=os.environ) + cred_path = cred_data['cred_path'] + if not os.path.exists(cred_path): msg = "Sync Server: No credentials for gdrive provider " + \ "for '{}' on path '{}'!".format(site_name, cred_path) From 4235a7674f6b37ff3b13fa9083a0114f558acb06 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Mon, 4 Apr 2022 19:39:24 +0200 Subject: [PATCH 13/58] Use format to fill cred_path --- .../modules/sync_server/providers/gdrive.py | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/openpype/modules/sync_server/providers/gdrive.py b/openpype/modules/sync_server/providers/gdrive.py index 6a8d2b3422..f7bb2d36df 100644 --- a/openpype/modules/sync_server/providers/gdrive.py +++ b/openpype/modules/sync_server/providers/gdrive.py @@ -3,7 +3,7 @@ import os.path import time import sys import six -import acre +import platform from openpype.api import Logger from openpype.api import get_system_settings @@ -73,12 +73,22 @@ class GDriveHandler(AbstractProvider): format(site_name)) return - cred_data = { - 'cred_path': self.presets.get("credentials_url", {}) - } - cred_data = acre.parse(cred_data) - cred_data = acre.merge(cred_data, current_env=os.environ) - cred_path = cred_data['cred_path'] + current_platform = platform.system().lower() + cred_path = self.presets.get("credentials_url", {}). \ + get(current_platform) or '' + + if not cred_path: + msg = "Sync Server: Please, fill the credentials for gdrive "\ + "provider for platform '{}' !".format(current_platform) + log.info(msg) + return + + try: + cred_path = cred_path.format(**os.environ) + except KeyError as e: + log.info("the key(s) {} does not exist in the environment " + "variables".format(" ".join(e.args))) + return if not os.path.exists(cred_path): msg = "Sync Server: No credentials for gdrive provider " + \ From 8896b36ef0c1a0295c09ef69097589aad765245b Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Mon, 4 Apr 2022 19:41:27 +0200 Subject: [PATCH 14/58] Replace t by T in log message --- openpype/modules/sync_server/providers/gdrive.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/sync_server/providers/gdrive.py b/openpype/modules/sync_server/providers/gdrive.py index f7bb2d36df..d6369d39e6 100644 --- a/openpype/modules/sync_server/providers/gdrive.py +++ b/openpype/modules/sync_server/providers/gdrive.py @@ -86,7 +86,7 @@ class GDriveHandler(AbstractProvider): try: cred_path = cred_path.format(**os.environ) except KeyError as e: - log.info("the key(s) {} does not exist in the environment " + log.info("The key(s) {} does not exist in the environment " "variables".format(" ".join(e.args))) return From 57ecd9adfaadc7e81e686a0bb74d68efaaf85b61 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Mon, 4 Apr 2022 19:43:13 +0200 Subject: [PATCH 15/58] Better log message with Sync Server --- openpype/modules/sync_server/providers/gdrive.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/modules/sync_server/providers/gdrive.py b/openpype/modules/sync_server/providers/gdrive.py index d6369d39e6..b783f7958b 100644 --- a/openpype/modules/sync_server/providers/gdrive.py +++ b/openpype/modules/sync_server/providers/gdrive.py @@ -86,8 +86,8 @@ class GDriveHandler(AbstractProvider): try: cred_path = cred_path.format(**os.environ) except KeyError as e: - log.info("The key(s) {} does not exist in the environment " - "variables".format(" ".join(e.args))) + log.info("Sync Server: The key(s) {} does not exist in the " + "environment variables".format(" ".join(e.args))) return if not os.path.exists(cred_path): From edac05b8507ee53cd485750b8821bfd49d7e72a1 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 5 Apr 2022 11:04:32 +0200 Subject: [PATCH 16/58] Added default subset template {family}{Task} for workfile family --- openpype/settings/defaults/project_settings/global.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/openpype/settings/defaults/project_settings/global.json b/openpype/settings/defaults/project_settings/global.json index 24334b0045..ffa63a8d81 100644 --- a/openpype/settings/defaults/project_settings/global.json +++ b/openpype/settings/defaults/project_settings/global.json @@ -243,6 +243,15 @@ "tasks": [], "template": "{family}{variant}" }, + { + "families": [ + "workfile" + ], + "hosts": [], + "task_types": [], + "tasks": [], + "template": "{family}{Task}" + }, { "families": [ "render" From 77d017bae2d97b1f22dda8e1bcf50ea9179adb9d Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 5 Apr 2022 11:06:26 +0200 Subject: [PATCH 17/58] Updated assert message for comparing results --- tests/lib/assert_classes.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/lib/assert_classes.py b/tests/lib/assert_classes.py index 98f758767d..7f4d8efc10 100644 --- a/tests/lib/assert_classes.py +++ b/tests/lib/assert_classes.py @@ -24,16 +24,18 @@ class DBAssert: else: args[key] = val - msg = None - no_of_docs = dbcon.count_documents(args) - if expected != no_of_docs: - msg = "Not expected no of versions. "\ - "Expected {}, found {}".format(expected, no_of_docs) - args.pop("type") detail_str = " " if args: - detail_str = " with {}".format(args) + detail_str = " with '{}'".format(args) + + msg = None + no_of_docs = dbcon.count_documents(args) + if expected != no_of_docs: + msg = "Not expected no of '{}'{}."\ + "Expected {}, found {}".format(queried_type, + detail_str, + expected, no_of_docs) status = "successful" if msg: @@ -42,7 +44,5 @@ class DBAssert: print("Comparing count of {}{} {}".format(queried_type, detail_str, status)) - if msg: - print(msg) return msg From b8d7dc0d6245256234ff4136181287b66adbb084 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 5 Apr 2022 18:36:17 +0200 Subject: [PATCH 18/58] changed hasReviewableRepresentations to useSequenceForReview --- .../publish/extract_review_data_mov.py | 2 +- .../plugins/publish/submit_publish_job.py | 46 ++++++++++--------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/extract_review_data_mov.py b/openpype/hosts/nuke/plugins/publish/extract_review_data_mov.py index 22b371d8e9..2e8843d2e0 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_review_data_mov.py +++ b/openpype/hosts/nuke/plugins/publish/extract_review_data_mov.py @@ -123,7 +123,7 @@ class ExtractReviewDataMov(openpype.api.Extractor): if generated_repres: # assign to representations instance.data["representations"] += generated_repres - instance.data["hasReviewableRepresentations"] = True + instance.data["useSequenceForReview"] = False else: instance.data["families"].remove("review") self.log.info(( diff --git a/openpype/modules/deadline/plugins/publish/submit_publish_job.py b/openpype/modules/deadline/plugins/publish/submit_publish_job.py index a8f4fec563..586d0f975a 100644 --- a/openpype/modules/deadline/plugins/publish/submit_publish_job.py +++ b/openpype/modules/deadline/plugins/publish/submit_publish_job.py @@ -524,26 +524,31 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): for collection in collections: ext = collection.tail.lstrip(".") preview = False - # if filtered aov name is found in filename, toggle it for - # preview video rendering - for app in self.aov_filter.keys(): - if os.environ.get("AVALON_APP", "") == app: - # no need to add review if `hasReviewableRepresentations` - if instance.get("hasReviewableRepresentations"): - break + # TODO 'useSequenceForReview' is temporary solution which does + # not work for 100% of cases. We must be able to tell what + # expected files contains more explicitly and from what + # should be review made. + # - "review" tag is never added when is set to 'False' + use_sequence_for_review = instance.get( + "useSequenceForReview", True + ) + if use_sequence_for_review: + # if filtered aov name is found in filename, toggle it for + # preview video rendering + for app in self.aov_filter.keys(): + if os.environ.get("AVALON_APP", "") == app: + # iteratre all aov filters + for aov in self.aov_filter[app]: + if re.match( + aov, + list(collection)[0] + ): + preview = True + break - # iteratre all aov filters - for aov in self.aov_filter[app]: - if re.match( - aov, - list(collection)[0] - ): - preview = True - break - - # toggle preview on if multipart is on - if instance.get("multipartExr", False): - preview = True + # toggle preview on if multipart is on + if instance.get("multipartExr", False): + preview = True staging = os.path.dirname(list(collection)[0]) success, rootless_staging_dir = ( @@ -730,8 +735,7 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): "resolutionHeight": data.get("resolutionHeight", 1080), "multipartExr": data.get("multipartExr", False), "jobBatchName": data.get("jobBatchName", ""), - "hasReviewableRepresentations": data.get( - "hasReviewableRepresentations") + "useSequenceForReview": data.get("useSequenceForReview") } if "prerender" in instance.data["families"]: From 7eb37b9e302c8894ed16140a1e44fab3893b7562 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 5 Apr 2022 18:46:38 +0200 Subject: [PATCH 19/58] changed how console splitter sizez are reused on show --- .../window/widgets.py | 46 +++++++++++++++++-- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/openpype/modules/python_console_interpreter/window/widgets.py b/openpype/modules/python_console_interpreter/window/widgets.py index ecf41eaf3e..9c6717ed17 100644 --- a/openpype/modules/python_console_interpreter/window/widgets.py +++ b/openpype/modules/python_console_interpreter/window/widgets.py @@ -389,7 +389,8 @@ class PythonInterpreterWidget(QtWidgets.QWidget): self._append_lines([openpype_art]) - self.setStyleSheet(load_stylesheet()) + self._first_show = True + self._splitter_size_ratio = None self._init_from_registry() @@ -416,9 +417,9 @@ class PythonInterpreterWidget(QtWidgets.QWidget): self.resize(width, height) try: - sizes = setting_registry.get_item("splitter_sizes") - if len(sizes) == len(self._widgets_splitter.sizes()): - self._widgets_splitter.setSizes(sizes) + self._splitter_size_ratio = ( + setting_registry.get_item("splitter_sizes") + ) except ValueError: pass @@ -627,8 +628,45 @@ class PythonInterpreterWidget(QtWidgets.QWidget): def showEvent(self, event): self._line_check_timer.start() super(PythonInterpreterWidget, self).showEvent(event) + # First show setup + if self._first_show: + self._first_show = False + self._on_first_show() + self._output_widget.scroll_to_bottom() + def _on_first_show(self): + # Change stylesheet + self.setStyleSheet(load_stylesheet()) + # Check if splitter size raio is set + # - first store value to local variable and then unset it + splitter_size_ratio = self._splitter_size_ratio + self._splitter_size_ratio = None + # Skip if is not set + if not splitter_size_ratio: + return + + # Skip if number of size items does not match to splitter + splitters_count = len(self._widgets_splitter.sizes()) + if len(splitter_size_ratio) != splitters_count: + return + + # Don't use absolute sizes but ratio of last stored sizes + ratio_sum = sum(splitter_size_ratio) + sizes = [] + max_size = self._widgets_splitter.height() + cur_size = 0 + ratio = max_size / ratio_sum + for size in splitter_size_ratio: + item_size = int(ratio * size) + cur_size += item_size + if cur_size > max_size: + item_size -= cur_size - max_size + if not item_size: + item_size = 1 + sizes.append(item_size) + self._widgets_splitter.setSizes(sizes) + def closeEvent(self, event): self.save_registry() super(PythonInterpreterWidget, self).closeEvent(event) From d740845a99e06073a905fee870bb923cfc862b95 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 6 Apr 2022 00:13:56 +0200 Subject: [PATCH 20/58] simplified set sizes --- .../window/widgets.py | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/openpype/modules/python_console_interpreter/window/widgets.py b/openpype/modules/python_console_interpreter/window/widgets.py index 9c6717ed17..6fdbc3ba2a 100644 --- a/openpype/modules/python_console_interpreter/window/widgets.py +++ b/openpype/modules/python_console_interpreter/window/widgets.py @@ -648,24 +648,8 @@ class PythonInterpreterWidget(QtWidgets.QWidget): # Skip if number of size items does not match to splitter splitters_count = len(self._widgets_splitter.sizes()) - if len(splitter_size_ratio) != splitters_count: - return - - # Don't use absolute sizes but ratio of last stored sizes - ratio_sum = sum(splitter_size_ratio) - sizes = [] - max_size = self._widgets_splitter.height() - cur_size = 0 - ratio = max_size / ratio_sum - for size in splitter_size_ratio: - item_size = int(ratio * size) - cur_size += item_size - if cur_size > max_size: - item_size -= cur_size - max_size - if not item_size: - item_size = 1 - sizes.append(item_size) - self._widgets_splitter.setSizes(sizes) + if len(splitter_size_ratio) == splitters_count: + self._widgets_splitter.setSizes(splitter_size_ratio) def closeEvent(self, event): self.save_registry() From e8a59ac056cbc91bdf57305d50e10d6f276ed773 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 6 Apr 2022 00:16:12 +0200 Subject: [PATCH 21/58] Fix typo in comment Co-authored-by: Roy Nieterau --- openpype/modules/python_console_interpreter/window/widgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/python_console_interpreter/window/widgets.py b/openpype/modules/python_console_interpreter/window/widgets.py index 6fdbc3ba2a..36ce1b61a2 100644 --- a/openpype/modules/python_console_interpreter/window/widgets.py +++ b/openpype/modules/python_console_interpreter/window/widgets.py @@ -638,7 +638,7 @@ class PythonInterpreterWidget(QtWidgets.QWidget): def _on_first_show(self): # Change stylesheet self.setStyleSheet(load_stylesheet()) - # Check if splitter size raio is set + # Check if splitter size ratio is set # - first store value to local variable and then unset it splitter_size_ratio = self._splitter_size_ratio self._splitter_size_ratio = None From 7bd1f630e732ca0ea92ebbc1ecf8646b90de0c7f Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 12:05:41 +0200 Subject: [PATCH 22/58] moved check of representations earlier --- .../plugins/publish/integrate_ftrack_instances.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_instances.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_instances.py index b54db918a6..b9a486d9da 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_instances.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_instances.py @@ -40,6 +40,13 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): def process(self, instance): self.log.debug("instance {}".format(instance)) + instance_repres = instance.data.get("representations") + if not instance_repres: + self.log.info(( + "Skipping instance. Does not have any representations {}" + ).format(str(instance))) + return + instance_version = instance.data.get("version") if instance_version is None: raise ValueError("Instance version not set") @@ -64,13 +71,6 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): ).format(family)) return - instance_repres = instance.data.get("representations") - if not instance_repres: - self.log.info(( - "Skipping instance. Does not have any representations {}" - ).format(str(instance))) - return - # Prepare FPS instance_fps = instance.data.get("fps") if instance_fps is None: From 66209b27cd0ad2efd90655ad352b66a2a043100a Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 12:05:56 +0200 Subject: [PATCH 23/58] added default asset type into integrate ftrack instances --- .../ftrack/plugins/publish/integrate_ftrack_instances.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_instances.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_instances.py index b9a486d9da..5ea0469bce 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_instances.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_instances.py @@ -60,8 +60,12 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): if not asset_type and family_low in self.family_mapping: asset_type = self.family_mapping[family_low] - self.log.debug(self.family_mapping) - self.log.debug(family_low) + if not asset_type: + asset_type = "upload" + + self.log.debug( + "Family: {}\nMapping: {}".format(family_low, self.family_mapping) + ) # Ignore this instance if neither "ftrackFamily" or a family mapping is # found. From b9dc19a046f061c9b495fe39fb812154e8cdaf5b Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 12:14:37 +0200 Subject: [PATCH 24/58] prepared functions to separate process function --- .../plugins/publish/integrate_ftrack_api.py | 346 ++++++++++++++++++ 1 file changed, 346 insertions(+) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_api.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_api.py index 6c25b9191e..8ea2d8411b 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_api.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_api.py @@ -464,3 +464,349 @@ class IntegrateFtrackApi(pyblish.api.InstancePlugin): for asset_version in used_asset_versions: if asset_version not in instance.data[asset_versions_key]: instance.data[asset_versions_key].append(asset_version) + + def _ensure_asset_types_exists(self, session, component_list): + """Make sure that all AssetType entities exists for integration. + + Returns: + dict: All asset types by short name. + """ + # Query existing asset types + asset_types = session.query("select id, short from AssetType").all() + # Stpore all existing short names + asset_type_shorts = {asset_type["short"] for asset_type in asset_types} + # Check which asset types are missing and store them + asset_type_names_by_missing_shorts = {} + default_short_name = "upload" + for data in component_list: + asset_type_data = data.get("assettype_data") or {} + asset_type_short = asset_type_data.get("short") + if not asset_type_short: + # Use default asset type name if not set and change the + # input data + asset_type_short = default_short_name + asset_type_data["short"] = asset_type_short + data["assettype_data"] = asset_type_data + + if ( + # Skip if short name exists + asset_type_short in asset_type_shorts + # Skip if short name was already added to missing types + # and asset type name is filled + # - if asset type name is missing then try use name from other + # data + or asset_type_names_by_missing_shorts.get(asset_type_short) + ): + continue + + asset_type_names_by_missing_shorts[asset_type_short] = ( + asset_type_data.get("name") + ) + + # Create missing asset types if there are any + if asset_type_names_by_missing_shorts: + self.log.info("Creating asset types with short names: {}".format( + ", ".join(asset_type_names_by_missing_shorts.keys()) + )) + for missing_short, type_name in asset_type_names_by_missing_shorts: + # Use short for name if name is not defined + if not type_name: + type_name = missing_short + # Use short name also for name + # - there is not other source for 'name' + session.create( + "AssetType", + { + "short": missing_short, + "name": type_name + } + ) + + # Commit creation + session.commit() + # Requery asset types + asset_types = session.query( + "select id, short from AssetType" + ).all() + + return {asset_type["short"]: asset_type for asset_type in asset_types} + + def _ensure_asset_exists( + self, session, asset_data, asset_type_id, parent_id + ): + asset_name = asset_data["name"] + asset_entity = self._query_asset( + session, asset_name, asset_type_id, parent_id + ) + if asset_entity is not None: + return asset_entity + + asset_data = { + "name": asset_name, + "type_id": asset_type_id, + "context_id": parent_id + } + self.log.info("Created new Asset with data: {}.".format(asset_data)) + session.create("Asset", asset_data) + session.commit() + return self._query_asset(session, asset_name, asset_type_id, parent_id) + + def _query_asset(self, session, asset_name, asset_type_id, parent_id): + return session.query( + ( + "select id from Asset" + " where name is \"{}\"" + " and type_id is \"{}\"" + " and context_id is \"{}\"" + ).format(asset_name, asset_type_id, parent_id) + ).first() + + def _ensure_asset_version_exists( + self, session, asset_version_data, asset_id, task_entity + ): + task_id = None + if task_entity: + task_id = task_entity["id"] + + # Try query asset version by criteria (asset id and version) + version = asset_version_data.get("version") or 0 + asset_version_entity = self._query_asset_version( + session, version, asset_id + ) + + # Prepare comment value + comment = asset_version_data.get("comment") or "" + if asset_version_entity is not None: + changed = False + if comment != asset_version_entity["comment"]: + asset_version_entity["comment"] = comment + changed = True + + if task_id != asset_version_entity["task_id"]: + asset_version_entity["task_id"] = task_id + changed = True + + if changed: + session.commit() + + else: + new_asset_version_data = { + "version": version, + "asset_id": asset_id + } + if task_id: + new_asset_version_data["task_id"] = task_id + + if comment: + new_asset_version_data["comment"] = comment + + self.log.info("Created new AssetVersion with data {}".format( + new_asset_version_data + )) + session.create("AssetVersion", new_asset_version_data) + session.commit() + asset_version_entity = self._query_asset_version( + session, version, asset_id + ) + + # Set custom attributes if there were any set + custom_attrs = asset_version_data.get("custom_attributes") or {} + for attr_key, attr_value in custom_attrs.items(): + if attr_key in asset_version_entity["custom_attributes"]: + try: + asset_version_entity["custom_attributes"][attr_key] = ( + attr_value + ) + session.commit() + continue + except Exception: + session.rollback() + session._configure_locations() + + self.log.warning( + ( + "Custom Attrubute \"{0}\" is not available for" + " AssetVersion <{1}>. Can't set it's value to: \"{2}\"" + ).format( + attr_key, asset_version_entity["id"], str(attr_value) + ) + ) + + return asset_version_entity + + def _query_asset_version(self, session, version, asset_id): + return session.query( + ( + "select id, task_id, comment from AssetVersion" + " where version is \"{}\" and asset_id is \"{}\"" + ).format(version, asset_id) + ).first() + + def create_component(self, session, asset_version_entity, data): + component_data = data.get("component_data") or {} + + if not component_data.get("name"): + component_data["name"] = "main" + + version_id = asset_version_entity["id"] + component_data["version_id"] = version_id + component_entity = session.query( + ( + "select id, name from Component where name is \"{}\"" + " and version_id is \"{}\"" + ).format(component_data["name"], version_id) + ).first() + + component_overwrite = data.get("component_overwrite", False) + location = data.get("component_location", session.pick_location()) + + # Overwrite existing component data if requested. + if component_entity and component_overwrite: + origin_location = session.query( + "Location where name is \"ftrack.origin\"" + ).one() + + # Removing existing members from location + components = list(component_entity.get("members", [])) + components += [component_entity] + for component in components: + for loc in component["component_locations"]: + if location["id"] == loc["location_id"]: + location.remove_component( + component, recursive=False + ) + + # Deleting existing members on component entity + for member in component_entity.get("members", []): + session.delete(member) + del(member) + + try: + session.commit() + except Exception: + tp, value, tb = sys.exc_info() + session.rollback() + session._configure_locations() + six.reraise(tp, value, tb) + + # Reset members in memory + if "members" in component_entity.keys(): + component_entity["members"] = [] + + # Add components to origin location + try: + collection = clique.parse(data["component_path"]) + except ValueError: + # Assume its a single file + # Changing file type + name, ext = os.path.splitext(data["component_path"]) + component_entity["file_type"] = ext + + origin_location.add_component( + component_entity, data["component_path"] + ) + else: + # Changing file type + component_entity["file_type"] = collection.format("{tail}") + + # Create member components for sequence. + for member_path in collection: + + size = 0 + try: + size = os.path.getsize(member_path) + except OSError: + pass + + name = collection.match(member_path).group("index") + + member_data = { + "name": name, + "container": component_entity, + "size": size, + "file_type": os.path.splitext(member_path)[-1] + } + + component = session.create( + "FileComponent", member_data + ) + origin_location.add_component( + component, member_path, recursive=False + ) + component_entity["members"].append(component) + + # Add components to location. + location.add_component( + component_entity, origin_location, recursive=True + ) + + data["component"] = component_entity + self.log.info( + ( + "Overwriting Component with path: {0}, data: {1}," + " location: {2}" + ).format( + data["component_path"], + component_data, + location + ) + ) + + # Extracting metadata, and adding after entity creation. This is + # due to a ftrack_api bug where you can't add metadata on creation. + component_metadata = component_data.pop("metadata", {}) + + # Create new component if none exists. + new_component = False + if not component_entity: + component_entity = asset_version_entity.create_component( + data["component_path"], + data=component_data, + location=location + ) + data["component"] = component_entity + self.log.info( + ( + "Created new Component with path: {0}, data: {1}," + " metadata: {2}, location: {3}" + ).format( + data["component_path"], + component_data, + component_metadata, + location + ) + ) + new_component = True + + # Adding metadata + existing_component_metadata = component_entity["metadata"] + existing_component_metadata.update(component_metadata) + component_entity["metadata"] = existing_component_metadata + + # if component_data['name'] = 'ftrackreview-mp4-mp4': + # assetversion_entity["thumbnail_id"] + + # Setting assetversion thumbnail + if data.get("thumbnail"): + asset_version_entity["thumbnail_id"] = component_entity["id"] + + # Inform user about no changes to the database. + if ( + component_entity + and not component_overwrite + and not new_component + ): + data["component"] = component_entity + self.log.info( + "Found existing component, and no request to overwrite. " + "Nothing has been changed." + ) + else: + # Commit changes. + try: + session.commit() + except Exception: + tp, value, tb = sys.exc_info() + session.rollback() + session._configure_locations() + six.reraise(tp, value, tb) From ad4fe059e8b90d4e2bda589c319b3ed2e5d94812 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 12:15:40 +0200 Subject: [PATCH 25/58] simplified process function of integrate ftrack api --- .../plugins/publish/integrate_ftrack_api.py | 468 ++++-------------- 1 file changed, 103 insertions(+), 365 deletions(-) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_api.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_api.py index 8ea2d8411b..7bba93c7cd 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_api.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_api.py @@ -1,3 +1,15 @@ +"""Integrate components into ftrack + +Requires: + context -> ftrackSession - connected ftrack.Session + instance -> ftrackComponentsList - list of components to integrate + +Provides: + instance -> ftrackIntegratedAssetVersionsData + # legacy + instance -> ftrackIntegratedAssetVersions +""" + import os import sys import six @@ -54,6 +66,97 @@ class IntegrateFtrackApi(pyblish.api.InstancePlugin): self.log.debug(query) return query + def process(self, instance): + session = instance.context.data["ftrackSession"] + context = instance.context + component_list = instance.data.get("ftrackComponentsList") + if not component_list: + self.log.info( + "Instance don't have components to integrate to Ftrack." + " Skipping." + ) + return + + session = instance.context.data["ftrackSession"] + context = instance.context + + parent_entity = None + default_asset_name = None + # If instance has set "ftrackEntity" or "ftrackTask" then use them from + # instance. Even if they are set to None. If they are set to None it + # has a reason. (like has different context) + if "ftrackEntity" in instance.data or "ftrackTask" in instance.data: + task_entity = instance.data.get("ftrackTask") + parent_entity = instance.data.get("ftrackEntity") + + elif "ftrackEntity" in context.data or "ftrackTask" in context.data: + task_entity = context.data.get("ftrackTask") + parent_entity = context.data.get("ftrackEntity") + + if task_entity: + default_asset_name = task_entity["name"] + parent_entity = task_entity["parent"] + + if parent_entity is None: + self.log.info(( + "Skipping ftrack integration. Instance \"{}\" does not" + " have specified ftrack entities." + ).format(str(instance))) + return + + if not default_asset_name: + default_asset_name = parent_entity["name"] + + # Change status on task + self._set_task_status(instance, task_entity, session) + + # Prepare AssetTypes + asset_types_by_short = self._ensure_asset_types_exists( + session, component_list + ) + + used_asset_versions = [] + # Iterate over components and publish + for data in component_list: + self.log.debug("data: {}".format(data)) + + # AssetType + asset_type_short = data["assettype_data"]["short"] + asset_type_entity = asset_types_by_short[asset_type_short] + + # Asset + asset_data = data.get("asset_data") or {} + if "name" not in asset_data: + asset_data["name"] = default_asset_name + asset_entity = self._ensure_asset_exists( + session, + asset_data, + asset_type_entity["id"], + parent_entity["id"] + ) + + # Asset Version + asset_version_data = data.get("assetversion_data") or {} + asset_version_entity = self._ensure_asset_version_exists( + session, asset_version_data, asset_entity["id"], task_entity + ) + + # Component + self.create_component(session, asset_version_entity, data) + + + # Backwards compatibility + if asset_version_entity not in used_asset_versions: + used_asset_versions.append(asset_version_entity) + + asset_versions_key = "ftrackIntegratedAssetVersions" + if asset_versions_key not in instance.data: + instance.data[asset_versions_key] = [] + + for asset_version in used_asset_versions: + if asset_version not in instance.data[asset_versions_key]: + instance.data[asset_versions_key].append(asset_version) + def _set_task_status(self, instance, task_entity, session): project_entity = instance.context.data.get("ftrackProject") if not project_entity: @@ -100,371 +203,6 @@ class IntegrateFtrackApi(pyblish.api.InstancePlugin): session._configure_locations() six.reraise(tp, value, tb) - def process(self, instance): - session = instance.context.data["ftrackSession"] - context = instance.context - - name = None - # If instance has set "ftrackEntity" or "ftrackTask" then use them from - # instance. Even if they are set to None. If they are set to None it - # has a reason. (like has different context) - if "ftrackEntity" in instance.data or "ftrackTask" in instance.data: - task = instance.data.get("ftrackTask") - parent = instance.data.get("ftrackEntity") - - elif "ftrackEntity" in context.data or "ftrackTask" in context.data: - task = context.data.get("ftrackTask") - parent = context.data.get("ftrackEntity") - - if task: - parent = task["parent"] - name = task - elif parent: - name = parent["name"] - - if not name: - self.log.info(( - "Skipping ftrack integration. Instance \"{}\" does not" - " have specified ftrack entities." - ).format(str(instance))) - return - - info_msg = ( - "Created new {entity_type} with data: {data}" - ", metadata: {metadata}." - ) - - used_asset_versions = [] - - self._set_task_status(instance, task, session) - - # Iterate over components and publish - for data in instance.data.get("ftrackComponentsList", []): - # AssetType - # Get existing entity. - assettype_data = {"short": "upload"} - assettype_data.update(data.get("assettype_data", {})) - self.log.debug("data: {}".format(data)) - - assettype_entity = session.query( - self.query("AssetType", assettype_data) - ).first() - - # Create a new entity if none exits. - if not assettype_entity: - assettype_entity = session.create("AssetType", assettype_data) - self.log.debug("Created new AssetType with data: {}".format( - assettype_data - )) - - # Asset - # Get existing entity. - asset_data = { - "name": name, - "type": assettype_entity, - "parent": parent, - } - asset_data.update(data.get("asset_data", {})) - - asset_entity = session.query( - self.query("Asset", asset_data) - ).first() - - self.log.info("asset entity: {}".format(asset_entity)) - - # Extracting metadata, and adding after entity creation. This is - # due to a ftrack_api bug where you can't add metadata on creation. - asset_metadata = asset_data.pop("metadata", {}) - - # Create a new entity if none exits. - if not asset_entity: - asset_entity = session.create("Asset", asset_data) - self.log.debug( - info_msg.format( - entity_type="Asset", - data=asset_data, - metadata=asset_metadata - ) - ) - try: - session.commit() - except Exception: - tp, value, tb = sys.exc_info() - session.rollback() - session._configure_locations() - six.reraise(tp, value, tb) - - # Adding metadata - existing_asset_metadata = asset_entity["metadata"] - existing_asset_metadata.update(asset_metadata) - asset_entity["metadata"] = existing_asset_metadata - - # AssetVersion - # Get existing entity. - assetversion_data = { - "version": 0, - "asset": asset_entity, - } - _assetversion_data = data.get("assetversion_data", {}) - assetversion_cust_attrs = _assetversion_data.pop( - "custom_attributes", {} - ) - asset_version_comment = _assetversion_data.pop( - "comment", None - ) - assetversion_data.update(_assetversion_data) - - assetversion_entity = session.query( - self.query("AssetVersion", assetversion_data) - ).first() - - # Extracting metadata, and adding after entity creation. This is - # due to a ftrack_api bug where you can't add metadata on creation. - assetversion_metadata = assetversion_data.pop("metadata", {}) - - if task: - assetversion_data['task'] = task - - # Create a new entity if none exits. - if not assetversion_entity: - assetversion_entity = session.create( - "AssetVersion", assetversion_data - ) - self.log.debug( - info_msg.format( - entity_type="AssetVersion", - data=assetversion_data, - metadata=assetversion_metadata - ) - ) - try: - session.commit() - except Exception: - tp, value, tb = sys.exc_info() - session.rollback() - session._configure_locations() - six.reraise(tp, value, tb) - - # Adding metadata - existing_assetversion_metadata = assetversion_entity["metadata"] - existing_assetversion_metadata.update(assetversion_metadata) - assetversion_entity["metadata"] = existing_assetversion_metadata - - # Add comment - if asset_version_comment: - assetversion_entity["comment"] = asset_version_comment - try: - session.commit() - except Exception: - session.rollback() - session._configure_locations() - self.log.warning(( - "Comment was not possible to set for AssetVersion" - "\"{0}\". Can't set it's value to: \"{1}\"" - ).format( - assetversion_entity["id"], str(asset_version_comment) - )) - - # Adding Custom Attributes - for attr, val in assetversion_cust_attrs.items(): - if attr in assetversion_entity["custom_attributes"]: - try: - assetversion_entity["custom_attributes"][attr] = val - session.commit() - continue - except Exception: - session.rollback() - session._configure_locations() - - self.log.warning(( - "Custom Attrubute \"{0}\"" - " is not available for AssetVersion <{1}>." - " Can't set it's value to: \"{2}\"" - ).format(attr, assetversion_entity["id"], str(val))) - - # Have to commit the version and asset, because location can't - # determine the final location without. - try: - session.commit() - except Exception: - tp, value, tb = sys.exc_info() - session.rollback() - session._configure_locations() - six.reraise(tp, value, tb) - - # Component - # Get existing entity. - component_data = { - "name": "main", - "version": assetversion_entity - } - component_data.update(data.get("component_data", {})) - - component_entity = session.query( - self.query("Component", component_data) - ).first() - - component_overwrite = data.get("component_overwrite", False) - location = data.get("component_location", session.pick_location()) - - # Overwrite existing component data if requested. - if component_entity and component_overwrite: - - origin_location = session.query( - "Location where name is \"ftrack.origin\"" - ).one() - - # Removing existing members from location - components = list(component_entity.get("members", [])) - components += [component_entity] - for component in components: - for loc in component["component_locations"]: - if location["id"] == loc["location_id"]: - location.remove_component( - component, recursive=False - ) - - # Deleting existing members on component entity - for member in component_entity.get("members", []): - session.delete(member) - del(member) - - try: - session.commit() - except Exception: - tp, value, tb = sys.exc_info() - session.rollback() - session._configure_locations() - six.reraise(tp, value, tb) - - # Reset members in memory - if "members" in component_entity.keys(): - component_entity["members"] = [] - - # Add components to origin location - try: - collection = clique.parse(data["component_path"]) - except ValueError: - # Assume its a single file - # Changing file type - name, ext = os.path.splitext(data["component_path"]) - component_entity["file_type"] = ext - - origin_location.add_component( - component_entity, data["component_path"] - ) - else: - # Changing file type - component_entity["file_type"] = collection.format("{tail}") - - # Create member components for sequence. - for member_path in collection: - - size = 0 - try: - size = os.path.getsize(member_path) - except OSError: - pass - - name = collection.match(member_path).group("index") - - member_data = { - "name": name, - "container": component_entity, - "size": size, - "file_type": os.path.splitext(member_path)[-1] - } - - component = session.create( - "FileComponent", member_data - ) - origin_location.add_component( - component, member_path, recursive=False - ) - component_entity["members"].append(component) - - # Add components to location. - location.add_component( - component_entity, origin_location, recursive=True - ) - - data["component"] = component_entity - msg = "Overwriting Component with path: {0}, data: {1}, " - msg += "location: {2}" - self.log.info( - msg.format( - data["component_path"], - component_data, - location - ) - ) - - # Extracting metadata, and adding after entity creation. This is - # due to a ftrack_api bug where you can't add metadata on creation. - component_metadata = component_data.pop("metadata", {}) - - # Create new component if none exists. - new_component = False - if not component_entity: - component_entity = assetversion_entity.create_component( - data["component_path"], - data=component_data, - location=location - ) - data["component"] = component_entity - msg = "Created new Component with path: {0}, data: {1}" - msg += ", metadata: {2}, location: {3}" - self.log.info( - msg.format( - data["component_path"], - component_data, - component_metadata, - location - ) - ) - new_component = True - - # Adding metadata - existing_component_metadata = component_entity["metadata"] - existing_component_metadata.update(component_metadata) - component_entity["metadata"] = existing_component_metadata - - # if component_data['name'] = 'ftrackreview-mp4-mp4': - # assetversion_entity["thumbnail_id"] - - # Setting assetversion thumbnail - if data.get("thumbnail", False): - assetversion_entity["thumbnail_id"] = component_entity["id"] - - # Inform user about no changes to the database. - if (component_entity and not component_overwrite and - not new_component): - data["component"] = component_entity - self.log.info( - "Found existing component, and no request to overwrite. " - "Nothing has been changed." - ) - else: - # Commit changes. - try: - session.commit() - except Exception: - tp, value, tb = sys.exc_info() - session.rollback() - session._configure_locations() - six.reraise(tp, value, tb) - - if assetversion_entity not in used_asset_versions: - used_asset_versions.append(assetversion_entity) - - asset_versions_key = "ftrackIntegratedAssetVersions" - if asset_versions_key not in instance.data: - instance.data[asset_versions_key] = [] - - for asset_version in used_asset_versions: - if asset_version not in instance.data[asset_versions_key]: - instance.data[asset_versions_key].append(asset_version) - def _ensure_asset_types_exists(self, session, component_list): """Make sure that all AssetType entities exists for integration. From 89d29a1d87ffe21e5d6d6d187ebb6e268bf289a1 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 12:16:03 +0200 Subject: [PATCH 26/58] store more data about asset versions in integrate ftrack api --- .../plugins/publish/integrate_ftrack_api.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_api.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_api.py index 7bba93c7cd..7ebf807f55 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_api.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_api.py @@ -115,6 +115,7 @@ class IntegrateFtrackApi(pyblish.api.InstancePlugin): session, component_list ) + asset_versions_data_by_id = {} used_asset_versions = [] # Iterate over components and publish for data in component_list: @@ -144,11 +145,27 @@ class IntegrateFtrackApi(pyblish.api.InstancePlugin): # Component self.create_component(session, asset_version_entity, data) + # Store asset version and components items that were + version_id = asset_version_entity["id"] + if version_id not in asset_versions_data_by_id: + asset_versions_data_by_id[version_id] = { + "asset_version": asset_version_entity, + "component_items": [] + } + + asset_versions_data_by_id[version_id]["component_items"].append( + data + ) # Backwards compatibility if asset_version_entity not in used_asset_versions: used_asset_versions.append(asset_version_entity) + instance.data["ftrackIntegratedAssetVersionsData"] = ( + asset_versions_data_by_id + ) + + # Backwards compatibility asset_versions_key = "ftrackIntegratedAssetVersions" if asset_versions_key not in instance.data: instance.data[asset_versions_key] = [] From 3d0238a6caba987a7d959de98354713518899ac3 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 1 Apr 2022 19:41:29 +0200 Subject: [PATCH 27/58] removed unused imports --- .../ftrack/event_handlers_user/action_create_folders.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/openpype/modules/ftrack/event_handlers_user/action_create_folders.py b/openpype/modules/ftrack/event_handlers_user/action_create_folders.py index d15a865124..0ed12bd03e 100644 --- a/openpype/modules/ftrack/event_handlers_user/action_create_folders.py +++ b/openpype/modules/ftrack/event_handlers_user/action_create_folders.py @@ -1,11 +1,6 @@ import os from openpype_modules.ftrack.lib import BaseAction, statics_icon -from avalon import lib as avalonlib -from openpype.api import ( - Anatomy, - get_project_settings -) -from openpype.lib import ApplicationManager +from openpype.api import Anatomy class CreateFolders(BaseAction): From 840daefb9fe188b91deefb40b3669caf5f4fb6bf Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 13:31:20 +0200 Subject: [PATCH 28/58] added example_addons into ignored filenames --- openpype/modules/base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/modules/base.py b/openpype/modules/base.py index 5cdeb86087..2d5545d135 100644 --- a/openpype/modules/base.py +++ b/openpype/modules/base.py @@ -37,6 +37,7 @@ IGNORED_DEFAULT_FILENAMES = ( "__init__.py", "base.py", "interfaces.py", + "example_addons", ) From 02afd4b915c078b0bf67b02a61a0244e819facb4 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 13:31:46 +0200 Subject: [PATCH 29/58] subfolder of module must have init file --- openpype/modules/base.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/openpype/modules/base.py b/openpype/modules/base.py index 2d5545d135..94aa8fca1b 100644 --- a/openpype/modules/base.py +++ b/openpype/modules/base.py @@ -304,7 +304,13 @@ def _load_modules(): fullpath = os.path.join(current_dir, filename) basename, ext = os.path.splitext(filename) - if not os.path.isdir(fullpath) and ext not in (".py", ): + if os.path.isdir(fullpath): + # Check existence of init fil + init_path = os.path.join(fullpath, "__init__.py") + if not os.path.exists(init_path): + continue + + elif ext not in (".py", ): continue try: @@ -342,7 +348,13 @@ def _load_modules(): fullpath = os.path.join(dirpath, filename) basename, ext = os.path.splitext(filename) - if not os.path.isdir(fullpath) and ext not in (".py", ): + if os.path.isdir(fullpath): + # Check existence of init fil + init_path = os.path.join(fullpath, "__init__.py") + if not os.path.exists(init_path): + continue + + elif ext not in (".py", ): continue # TODO add more logic how to define if folder is module or not From 062b584ecbc47c46f5f3933d346ffdf67cb6d48b Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 13:41:31 +0200 Subject: [PATCH 30/58] added default_modules subfolder into ignored filenames --- openpype/modules/base.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openpype/modules/base.py b/openpype/modules/base.py index 94aa8fca1b..23c908299f 100644 --- a/openpype/modules/base.py +++ b/openpype/modules/base.py @@ -38,6 +38,7 @@ IGNORED_DEFAULT_FILENAMES = ( "base.py", "interfaces.py", "example_addons", + "default_modules", ) @@ -308,6 +309,9 @@ def _load_modules(): # Check existence of init fil init_path = os.path.join(fullpath, "__init__.py") if not os.path.exists(init_path): + log.debug(( + "Module directory does not contan __init__.py file {}" + ).format(fullpath)) continue elif ext not in (".py", ): @@ -352,6 +356,9 @@ def _load_modules(): # Check existence of init fil init_path = os.path.join(fullpath, "__init__.py") if not os.path.exists(init_path): + log.debug(( + "Module directory does not contan __init__.py file {}" + ).format(fullpath)) continue elif ext not in (".py", ): From 4da7f7c1cce65434d385bf8cad5dc678226c62e4 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 13:48:21 +0200 Subject: [PATCH 31/58] changed integrate ftrack note to b able add published paths into asset version comment --- .../plugins/publish/integrate_ftrack_note.py | 196 +++++++++--------- .../defaults/project_settings/ftrack.json | 2 +- .../defaults/project_settings/global.json | 2 +- .../schema_project_ftrack.json | 8 +- 4 files changed, 111 insertions(+), 97 deletions(-) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py index acd295854d..c165e99918 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py @@ -15,10 +15,112 @@ class IntegrateFtrackNote(pyblish.api.InstancePlugin): # Can be set in presets: # - Allows only `intent` and `comment` keys + note_template = None + # Backwards compatibility note_with_intent_template = "{intent}: {comment}" # - note label must exist in Ftrack note_labels = [] + def process(self, instance): + # Check if there are any integrated AssetVersion entities + asset_versions_key = "ftrackIntegratedAssetVersionsData" + asset_versions_data_by_id = instance.data.get(asset_versions_key) + if not asset_versions_data_by_id: + self.log.info("There are any integrated AssetVersions") + return + + comment = (instance.context.data.get("comment") or "").strip() + if not comment: + self.log.info("Comment is not set.") + else: + self.log.debug("Comment is set to `{}`".format(comment)) + + session = instance.context.data["ftrackSession"] + + intent = instance.context.data.get("intent") + if intent and isinstance(intent, dict): + intent_val = intent.get("value") + intent_label = intent.get("label") + else: + intent_val = intent_label = intent + + final_intent_label = None + if intent_val: + final_intent_label = self.get_intent_label(session, intent_val) + if final_intent_label is None: + final_intent_label = intent_label + + # if intent label is set then format comment + # - it is possible that intent_label is equal to "" (empty string) + if final_intent_label: + self.log.debug( + "Intent label is set to `{}`.".format(final_intent_label) + ) + + elif intent_val: + self.log.debug(( + "Intent is set to `{}` and was not added" + " to comment because label is set to `{}`." + ).format(intent_val, final_intent_label)) + + else: + self.log.debug("Intent is not set.") + + user = session.query( + "User where username is \"{}\"".format(session.api_user) + ).first() + if not user: + self.log.warning( + "Was not able to query current User {}".format( + session.api_user + ) + ) + + labels = [] + if self.note_labels: + all_labels = session.query("select id, name from NoteLabel").all() + labels_by_low_name = {lab["name"].lower(): lab for lab in all_labels} + for _label in self.note_labels: + label = labels_by_low_name.get(_label.lower()) + if not label: + self.log.warning( + "Note Label `{}` was not found.".format(_label) + ) + continue + + labels.append(label) + + for asset_version_data in asset_versions_data_by_id.values(): + asset_version = asset_version_data["asset_version"] + component_items = asset_version_data["component_items"] + + published_paths = set() + for component_item in component_items: + published_paths.add(component_item["component_path"]) + + # Backwards compatibility for older settings using + # attribute 'note_with_intent_template' + template = self.note_template + if template is None: + template = self.note_with_intent_template + comment = template.format(**{ + "intent": final_intent_label, + "comment": comment, + "published_paths": "\n".join(sorted(published_paths)) + }) + asset_version.create_note(comment, author=user, labels=labels) + + try: + session.commit() + self.log.debug("Note added to AssetVersion \"{}\"".format( + str(asset_version) + )) + except Exception: + tp, value, tb = sys.exc_info() + session.rollback() + session._configure_locations() + six.reraise(tp, value, tb) + def get_intent_label(self, session, intent_value): if not intent_value: return @@ -45,12 +147,7 @@ class IntegrateFtrackNote(pyblish.api.InstancePlugin): if not items: return - if sys.version_info[0] < 3: - string_type = basestring - else: - string_type = str - - if isinstance(items, string_type): + if isinstance(items, six.string_types): items = json.loads(items) intent_label = None @@ -60,90 +157,3 @@ class IntegrateFtrackNote(pyblish.api.InstancePlugin): break return intent_label - - def process(self, instance): - comment = (instance.context.data.get("comment") or "").strip() - if not comment: - self.log.info("Comment is not set.") - return - - self.log.debug("Comment is set to `{}`".format(comment)) - - session = instance.context.data["ftrackSession"] - - intent = instance.context.data.get("intent") - if intent and isinstance(intent, dict): - intent_val = intent.get("value") - intent_label = intent.get("label") - else: - intent_val = intent_label = intent - - final_label = None - if intent_val: - final_label = self.get_intent_label(session, intent_val) - if final_label is None: - final_label = intent_label - - # if intent label is set then format comment - # - it is possible that intent_label is equal to "" (empty string) - if final_label: - msg = "Intent label is set to `{}`.".format(final_label) - comment = self.note_with_intent_template.format(**{ - "intent": final_label, - "comment": comment - }) - - elif intent_val: - msg = ( - "Intent is set to `{}` and was not added" - " to comment because label is set to `{}`." - ).format(intent_val, final_label) - - else: - msg = "Intent is not set." - - self.log.debug(msg) - - asset_versions_key = "ftrackIntegratedAssetVersions" - asset_versions = instance.data.get(asset_versions_key) - if not asset_versions: - self.log.info("There are any integrated AssetVersions") - return - - user = session.query( - "User where username is \"{}\"".format(session.api_user) - ).first() - if not user: - self.log.warning( - "Was not able to query current User {}".format( - session.api_user - ) - ) - - labels = [] - if self.note_labels: - all_labels = session.query("NoteLabel").all() - labels_by_low_name = {lab["name"].lower(): lab for lab in all_labels} - for _label in self.note_labels: - label = labels_by_low_name.get(_label.lower()) - if not label: - self.log.warning( - "Note Label `{}` was not found.".format(_label) - ) - continue - - labels.append(label) - - for asset_version in asset_versions: - asset_version.create_note(comment, author=user, labels=labels) - - try: - session.commit() - self.log.debug("Note added to AssetVersion \"{}\"".format( - str(asset_version) - )) - except Exception: - tp, value, tb = sys.exc_info() - session.rollback() - session._configure_locations() - six.reraise(tp, value, tb) diff --git a/openpype/settings/defaults/project_settings/ftrack.json b/openpype/settings/defaults/project_settings/ftrack.json index ca1cfe1e12..9b350ec88d 100644 --- a/openpype/settings/defaults/project_settings/ftrack.json +++ b/openpype/settings/defaults/project_settings/ftrack.json @@ -354,7 +354,7 @@ }, "IntegrateFtrackNote": { "enabled": true, - "note_with_intent_template": "{intent}: {comment}", + "note_template": "{intent}: {comment}", "note_labels": [] }, "ValidateFtrackAttributes": { diff --git a/openpype/settings/defaults/project_settings/global.json b/openpype/settings/defaults/project_settings/global.json index ed28d357f2..4c94eee254 100644 --- a/openpype/settings/defaults/project_settings/global.json +++ b/openpype/settings/defaults/project_settings/global.json @@ -190,7 +190,7 @@ "tasks": [], "template_name": "simpleUnrealTexture" }, - { + { "families": [ "staticMesh", "skeletalMesh" diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json index fb384882c6..2b62d67c98 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json @@ -738,10 +738,14 @@ "key": "enabled", "label": "Enabled" }, + { + "type": "label", + "label": "Template may contain formatting keys {intent}, {comment} and {published_paths}." + }, { "type": "text", - "key": "note_with_intent_template", - "label": "Note with intent template" + "key": "note_template", + "label": "Note template" }, { "type": "list", From e3cfc6cc25fc0698a8719d2df38cddb40952e008 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 6 Apr 2022 15:09:06 +0200 Subject: [PATCH 32/58] Added creating subset name for workfile from template --- .../aftereffects/plugins/publish/collect_workfile.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/aftereffects/plugins/publish/collect_workfile.py b/openpype/hosts/aftereffects/plugins/publish/collect_workfile.py index c1c2be4855..cb5a2bad4f 100644 --- a/openpype/hosts/aftereffects/plugins/publish/collect_workfile.py +++ b/openpype/hosts/aftereffects/plugins/publish/collect_workfile.py @@ -1,6 +1,7 @@ import os from avalon import api import pyblish.api +from openpype.lib import get_subset_name_with_asset_doc class CollectWorkfile(pyblish.api.ContextPlugin): @@ -38,7 +39,14 @@ class CollectWorkfile(pyblish.api.ContextPlugin): # workfile instance family = "workfile" - subset = family + task.capitalize() + subset = get_subset_name_with_asset_doc( + family, + "", + context.data["anatomyData"]["task"]["name"], + context.data["assetEntity"], + context.data["anatomyData"]["project"]["name"], + host_name=context.data["hostName"] + ) # Create instance instance = context.create_instance(subset) From 57404e5bcd0bc382993af9554c7be71a430dd174 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 6 Apr 2022 15:22:56 +0200 Subject: [PATCH 33/58] Added creating subset name for workfile from template for Harmony --- .../harmony/plugins/publish/collect_workfile.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/harmony/plugins/publish/collect_workfile.py b/openpype/hosts/harmony/plugins/publish/collect_workfile.py index 63bfd5929b..c0493315a4 100644 --- a/openpype/hosts/harmony/plugins/publish/collect_workfile.py +++ b/openpype/hosts/harmony/plugins/publish/collect_workfile.py @@ -3,6 +3,8 @@ import pyblish.api import os +from openpype.lib import get_subset_name_with_asset_doc + class CollectWorkfile(pyblish.api.ContextPlugin): """Collect current script for publish.""" @@ -14,10 +16,15 @@ class CollectWorkfile(pyblish.api.ContextPlugin): def process(self, context): """Plugin entry point.""" family = "workfile" - task = os.getenv("AVALON_TASK", None) - sanitized_task_name = task[0].upper() + task[1:] basename = os.path.basename(context.data["currentFile"]) - subset = "{}{}".format(family, sanitized_task_name) + subset = get_subset_name_with_asset_doc( + family, + "", + context.data["anatomyData"]["task"]["name"], + context.data["assetEntity"], + context.data["anatomyData"]["project"]["name"], + host_name=context.data["hostName"] + ) # Create instance instance = context.create_instance(subset) From 8167a65f597b6526e69a66a5591f86c2b5c8aa54 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 15:26:53 +0200 Subject: [PATCH 34/58] added more checks --- .../plugins/publish/integrate_ftrack_note.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py index c165e99918..a77b6d6674 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py @@ -47,8 +47,9 @@ class IntegrateFtrackNote(pyblish.api.InstancePlugin): final_intent_label = None if intent_val: final_intent_label = self.get_intent_label(session, intent_val) - if final_intent_label is None: - final_intent_label = intent_label + + if final_intent_label is None: + final_intent_label = intent_label # if intent label is set then format comment # - it is possible that intent_label is equal to "" (empty string) @@ -103,11 +104,18 @@ class IntegrateFtrackNote(pyblish.api.InstancePlugin): template = self.note_template if template is None: template = self.note_with_intent_template - comment = template.format(**{ + format_data = { "intent": final_intent_label, "comment": comment, "published_paths": "\n".join(sorted(published_paths)) - }) + } + comment = template.format(**format_data) + if not comment: + self.log.info(( + "Note for AssetVersion {} would be empty. Skipping." + "\nTemplate: {}\nData: {}" + ).format(asset_version["id"], template, format_data)) + continue asset_version.create_note(comment, author=user, labels=labels) try: From fe39d0a300fd1ad76390f152cd8502a6f798c244 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 15:39:50 +0200 Subject: [PATCH 35/58] add host name to possible keys in template --- .../modules/ftrack/plugins/publish/integrate_ftrack_note.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py index a77b6d6674..8609e8bca6 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py @@ -29,6 +29,7 @@ class IntegrateFtrackNote(pyblish.api.InstancePlugin): self.log.info("There are any integrated AssetVersions") return + host_name = instance.context.data["hostName"] comment = (instance.context.data.get("comment") or "").strip() if not comment: self.log.info("Comment is not set.") @@ -107,7 +108,8 @@ class IntegrateFtrackNote(pyblish.api.InstancePlugin): format_data = { "intent": final_intent_label, "comment": comment, - "published_paths": "\n".join(sorted(published_paths)) + "host_name": host_name, + "published_paths": "\n".join(sorted(published_paths)), } comment = template.format(**format_data) if not comment: From 04b8eaf2998eb3269800df0d8fa4985a4a6a8df0 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 15:44:30 +0200 Subject: [PATCH 36/58] added new key into settings label --- .../entities/schemas/projects_schema/schema_project_ftrack.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json index 2b62d67c98..b3c094e398 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json @@ -740,7 +740,7 @@ }, { "type": "label", - "label": "Template may contain formatting keys {intent}, {comment} and {published_paths}." + "label": "Template may contain formatting keys {intent}, {comment}, {host_name} and {published_paths}." }, { "type": "text", From 00406a737610dc4623ff78edda1e7369ddbfc3f0 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 16:13:50 +0200 Subject: [PATCH 37/58] added more information abou app - name and label --- .../plugins/publish/collect_app_name.py | 13 +++++++++ .../plugins/publish/collect_app_name.py | 13 +++++++++ openpype/plugins/publish/collect_host_name.py | 28 +++++++++++++------ 3 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 openpype/hosts/standalonepublisher/plugins/publish/collect_app_name.py create mode 100644 openpype/hosts/traypublisher/plugins/publish/collect_app_name.py diff --git a/openpype/hosts/standalonepublisher/plugins/publish/collect_app_name.py b/openpype/hosts/standalonepublisher/plugins/publish/collect_app_name.py new file mode 100644 index 0000000000..857f3dca20 --- /dev/null +++ b/openpype/hosts/standalonepublisher/plugins/publish/collect_app_name.py @@ -0,0 +1,13 @@ +import pyblish.api + + +class CollectSAAppName(pyblish.api.ContextPlugin): + """Collect app name and label.""" + + label = "Collect App Name/Label" + order = pyblish.api.CollectorOrder - 0.5 + hosts = ["standalonepublisher"] + + def process(self, context): + context.data["appName"] = "standalone publisher" + context.data["appLabel"] = "Standalone publisher" diff --git a/openpype/hosts/traypublisher/plugins/publish/collect_app_name.py b/openpype/hosts/traypublisher/plugins/publish/collect_app_name.py new file mode 100644 index 0000000000..e38d10e70f --- /dev/null +++ b/openpype/hosts/traypublisher/plugins/publish/collect_app_name.py @@ -0,0 +1,13 @@ +import pyblish.api + + +class CollectTrayPublisherAppName(pyblish.api.ContextPlugin): + """Collect app name and label.""" + + label = "Collect App Name/Label" + order = pyblish.api.CollectorOrder - 0.5 + hosts = ["traypublisher"] + + def process(self, context): + context.data["appName"] = "tray publisher" + context.data["appLabel"] = "Tray publisher" diff --git a/openpype/plugins/publish/collect_host_name.py b/openpype/plugins/publish/collect_host_name.py index b731e3ed26..d64af4d049 100644 --- a/openpype/plugins/publish/collect_host_name.py +++ b/openpype/plugins/publish/collect_host_name.py @@ -18,20 +18,30 @@ class CollectHostName(pyblish.api.ContextPlugin): def process(self, context): host_name = context.data.get("hostName") + app_name = context.data.get("appName") + app_label = context.data.get("appLabel") # Don't override value if is already set - if host_name: + if host_name and app_name and app_label: return - # Use AVALON_APP as first if available it is the same as host name - # - only if is not defined use AVALON_APP_NAME (e.g. on Farm) and - # set it back to AVALON_APP env variable - host_name = os.environ.get("AVALON_APP") + # Use AVALON_APP to get host name if available if not host_name: + host_name = os.environ.get("AVALON_APP") + + # Use AVALON_APP_NAME to get full app name + if not app_name: app_name = os.environ.get("AVALON_APP_NAME") - if app_name: - app_manager = ApplicationManager() - app = app_manager.applications.get(app_name) - if app: + + # Fill missing values based on app full name + if (not host_name or not app_label) and app_name: + app_manager = ApplicationManager() + app = app_manager.applications.get(app_name) + if app: + if not host_name: host_name = app.host_name + if not app_label: + app_label = app.full_label context.data["hostName"] = host_name + context.data["appName"] = app_name + context.data["appLabel"] = app_label From e68a7cbf7bb9c4362bd5c64ad617ec38db9c633b Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 16:15:40 +0200 Subject: [PATCH 38/58] added app name and lable keys into note template --- .../modules/ftrack/plugins/publish/integrate_ftrack_note.py | 4 ++++ .../schemas/projects_schema/schema_project_ftrack.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py index 8609e8bca6..8220b8e6ca 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py @@ -30,6 +30,8 @@ class IntegrateFtrackNote(pyblish.api.InstancePlugin): return host_name = instance.context.data["hostName"] + app_name = instance.context.data["appName"] + app_label = instance.context.data["appLabel"] comment = (instance.context.data.get("comment") or "").strip() if not comment: self.log.info("Comment is not set.") @@ -109,6 +111,8 @@ class IntegrateFtrackNote(pyblish.api.InstancePlugin): "intent": final_intent_label, "comment": comment, "host_name": host_name, + "app_name": app_name, + "app_label": app_label, "published_paths": "\n".join(sorted(published_paths)), } comment = template.format(**format_data) diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json index b3c094e398..0d7faac2ba 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json @@ -740,7 +740,7 @@ }, { "type": "label", - "label": "Template may contain formatting keys {intent}, {comment}, {host_name} and {published_paths}." + "label": "Template may contain formatting keys intent, comment, host_name, app_name, app_label and published_paths." }, { "type": "text", From 2a3460e0fa57408356a2af0ebfcba33ad83f4132 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 16:15:55 +0200 Subject: [PATCH 39/58] changed note template input into multiline input --- .../schemas/projects_schema/schema_project_ftrack.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json index 0d7faac2ba..0ed2fb3536 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json @@ -745,7 +745,8 @@ { "type": "text", "key": "note_template", - "label": "Note template" + "label": "Note template", + "multiline": true }, { "type": "list", From 2e9b7325e47c30a75850c048669c2e04d8bbf3de Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 16:25:27 +0200 Subject: [PATCH 40/58] change new line char with br/ html tag --- .../modules/ftrack/plugins/publish/integrate_ftrack_note.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py index 8220b8e6ca..3a9f904d00 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py @@ -113,7 +113,7 @@ class IntegrateFtrackNote(pyblish.api.InstancePlugin): "host_name": host_name, "app_name": app_name, "app_label": app_label, - "published_paths": "\n".join(sorted(published_paths)), + "published_paths": "
".join(sorted(published_paths)), } comment = template.format(**format_data) if not comment: From dff1a51f96a1237071e2fe2ed3cac400c7a3bf6e Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 16:33:05 +0200 Subject: [PATCH 41/58] removed outdated log --- .../modules/ftrack/plugins/publish/integrate_ftrack_note.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py index 3a9f904d00..56a7a89e16 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py @@ -61,12 +61,6 @@ class IntegrateFtrackNote(pyblish.api.InstancePlugin): "Intent label is set to `{}`.".format(final_intent_label) ) - elif intent_val: - self.log.debug(( - "Intent is set to `{}` and was not added" - " to comment because label is set to `{}`." - ).format(intent_val, final_intent_label)) - else: self.log.debug("Intent is not set.") From 86647e02310d0913afd7919d364f6c07bf2274e4 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 17:26:53 +0200 Subject: [PATCH 42/58] added collector for intent label --- .../plugins/publish/collect_intent_label.py | 78 +++++++++++++++++ .../plugins/publish/integrate_ftrack_note.py | 83 +++++-------------- 2 files changed, 101 insertions(+), 60 deletions(-) create mode 100644 openpype/modules/ftrack/plugins/publish/collect_intent_label.py diff --git a/openpype/modules/ftrack/plugins/publish/collect_intent_label.py b/openpype/modules/ftrack/plugins/publish/collect_intent_label.py new file mode 100644 index 0000000000..c23722933c --- /dev/null +++ b/openpype/modules/ftrack/plugins/publish/collect_intent_label.py @@ -0,0 +1,78 @@ +""" +Requires: + context -> ftrackSession - connected ftrack.Session + +Provides: + context -> ftrackIntentLabel +""" +import json + +import six +import pyblish.api + + +class CollectFtrackApi(pyblish.api.ContextPlugin): + """ Collects an ftrack session and the current task id. """ + + order = pyblish.api.CollectorOrder + 0.49991 + label = "Collect Ftrack Intent Label" + + def process(self, context): + intent = context.data.get("intent") + if intent and isinstance(intent, dict): + intent_val = intent.get("value") + intent_label = intent.get("label") + else: + intent_val = intent_label = intent + + session = context.data.get("ftrackSession") + if session is None: + context.data["ftrackIntentLabel"] = intent_label + self.log.info("Ftrack session is not available. Skipping.") + return + + final_intent_label = None + if intent_val: + final_intent_label = self.get_intent_label(session, intent_val) + + if final_intent_label is None: + final_intent_label = intent_label + + context.data["ftrackIntentLabel"] = final_intent_label + + def get_intent_label(self, session, intent_value): + if not intent_value: + return + + intent_configurations = session.query( + "CustomAttributeConfiguration where key is intent" + ).all() + if not intent_configurations: + return + + intent_configuration = intent_configurations[0] + if len(intent_configuration) > 1: + self.log.warning(( + "Found more than one `intent` custom attribute." + " Using first found." + )) + + config = intent_configuration.get("config") + if not config: + return + + configuration = json.loads(config) + items = configuration.get("data") + if not items: + return + + if isinstance(items, six.string_types): + items = json.loads(items) + + intent_label = None + for item in items: + if item["value"] == intent_value: + intent_label = item["menu"] + break + + return intent_label diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py index 56a7a89e16..2fe97dc7ac 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py @@ -1,7 +1,18 @@ +""" +Requires: + context > hostName + context > appName + context > appLabel + context > comment + context > ftrackSession + context > ftrackIntentLabel + instance > ftrackIntegratedAssetVersionsData +""" + import sys -import json -import pyblish.api + import six +import pyblish.api class IntegrateFtrackNote(pyblish.api.InstancePlugin): @@ -29,36 +40,25 @@ class IntegrateFtrackNote(pyblish.api.InstancePlugin): self.log.info("There are any integrated AssetVersions") return - host_name = instance.context.data["hostName"] - app_name = instance.context.data["appName"] - app_label = instance.context.data["appLabel"] - comment = (instance.context.data.get("comment") or "").strip() + context = instance.context + host_name = context.data["hostName"] + app_name = context.data["appName"] + app_label = context.data["appLabel"] + comment = (context.data.get("comment") or "").strip() if not comment: self.log.info("Comment is not set.") else: self.log.debug("Comment is set to `{}`".format(comment)) - session = instance.context.data["ftrackSession"] + session = context.data["ftrackSession"] - intent = instance.context.data.get("intent") - if intent and isinstance(intent, dict): - intent_val = intent.get("value") - intent_label = intent.get("label") - else: - intent_val = intent_label = intent - - final_intent_label = None - if intent_val: - final_intent_label = self.get_intent_label(session, intent_val) - - if final_intent_label is None: - final_intent_label = intent_label + intent_label = context.data["ftrackIntentLabel"] # if intent label is set then format comment # - it is possible that intent_label is equal to "" (empty string) - if final_intent_label: + if intent_label: self.log.debug( - "Intent label is set to `{}`.".format(final_intent_label) + "Intent label is set to `{}`.".format(intent_label) ) else: @@ -102,7 +102,7 @@ class IntegrateFtrackNote(pyblish.api.InstancePlugin): if template is None: template = self.note_with_intent_template format_data = { - "intent": final_intent_label, + "intent": intent_label, "comment": comment, "host_name": host_name, "app_name": app_name, @@ -128,40 +128,3 @@ class IntegrateFtrackNote(pyblish.api.InstancePlugin): session.rollback() session._configure_locations() six.reraise(tp, value, tb) - - def get_intent_label(self, session, intent_value): - if not intent_value: - return - - intent_configurations = session.query( - "CustomAttributeConfiguration where key is intent" - ).all() - if not intent_configurations: - return - - intent_configuration = intent_configurations[0] - if len(intent_configuration) > 1: - self.log.warning(( - "Found more than one `intent` custom attribute." - " Using first found." - )) - - config = intent_configuration.get("config") - if not config: - return - - configuration = json.loads(config) - items = configuration.get("data") - if not items: - return - - if isinstance(items, six.string_types): - items = json.loads(items) - - intent_label = None - for item in items: - if item["value"] == intent_value: - intent_label = item["menu"] - break - - return intent_label From e277cb8ed87be7e7591ae76e048f183c5bf6ce27 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 17:28:39 +0200 Subject: [PATCH 43/58] added ftrack integrator adding comment to description --- .../publish/integrate_ftrack_description.py | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 openpype/modules/ftrack/plugins/publish/integrate_ftrack_description.py diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_description.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_description.py new file mode 100644 index 0000000000..7e8371cd9d --- /dev/null +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_description.py @@ -0,0 +1,76 @@ +""" +Requires: + context > comment + context > ftrackSession + context > ftrackIntentLabel + instance > ftrackIntegratedAssetVersionsData +""" + +import sys + +import six +import pyblish.api + + +class IntegrateFtrackDescription(pyblish.api.InstancePlugin): + """Add description to AssetVersions in Ftrack.""" + + # Must be after integrate asset new + order = pyblish.api.IntegratorOrder + 0.4999 + label = "Integrate Ftrack description" + families = ["ftrack"] + optional = True + + # Can be set in settings: + # - Allows `intent` and `comment` keys + description_template = "{comment}" + + def process(self, instance): + # Check if there are any integrated AssetVersion entities + asset_versions_key = "ftrackIntegratedAssetVersionsData" + asset_versions_data_by_id = instance.data.get(asset_versions_key) + if not asset_versions_data_by_id: + self.log.info("There are any integrated AssetVersions") + return + + comment = (instance.context.data.get("comment") or "").strip() + if not comment: + self.log.info("Comment is not set.") + else: + self.log.debug("Comment is set to `{}`".format(comment)) + + session = instance.context.data["ftrackSession"] + + intent_label = instance.context.data["ftrackIntentLabel"] + + # if intent label is set then format comment + # - it is possible that intent_label is equal to "" (empty string) + if intent_label: + self.log.debug( + "Intent label is set to `{}`.".format(intent_label) + ) + + else: + self.log.debug("Intent is not set.") + + for asset_version_data in asset_versions_data_by_id.values(): + asset_version = asset_version_data["asset_version"] + + # Backwards compatibility for older settings using + # attribute 'note_with_intent_template' + comment = self.description_template.format(**{ + "intent": intent_label, + "comment": comment + }) + asset_version["comment"] = comment + + try: + session.commit() + self.log.debug("Comment added to AssetVersion \"{}\"".format( + str(asset_version) + )) + except Exception: + tp, value, tb = sys.exc_info() + session.rollback() + session._configure_locations() + six.reraise(tp, value, tb) From 49808788f03f07037cb4c21270a1510c235d9ca1 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 17:41:54 +0200 Subject: [PATCH 44/58] added settings for integrate ftrack description --- .../defaults/project_settings/ftrack.json | 6 +++ .../schema_project_ftrack.json | 38 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/openpype/settings/defaults/project_settings/ftrack.json b/openpype/settings/defaults/project_settings/ftrack.json index 9b350ec88d..31d6a70ac7 100644 --- a/openpype/settings/defaults/project_settings/ftrack.json +++ b/openpype/settings/defaults/project_settings/ftrack.json @@ -357,6 +357,12 @@ "note_template": "{intent}: {comment}", "note_labels": [] }, + "IntegrateFtrackDescription": { + "enabled": false, + "optional": true, + "active": true, + "description_template": "{comment}" + }, "ValidateFtrackAttributes": { "enabled": false, "ftrack_custom_attributes": {} diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json index 0ed2fb3536..5ce9b24b4b 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json @@ -756,6 +756,44 @@ } ] }, + { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "key": "IntegrateFtrackDescription", + "label": "Integrate Ftrack Description", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "label", + "label": "Add description to integrated AssetVersion." + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + }, + { + "type": "label", + "label": "Template may contain formatting keys intent and comment." + }, + { + "type": "text", + "key": "description_template", + "label": "Description template" + } + ] + }, { "type": "dict", "collapsible": true, From 68957cc0d9e545be7328dc484aaa22b4039b10b8 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 18:14:34 +0200 Subject: [PATCH 45/58] changed name of publish plugin --- openpype/modules/ftrack/plugins/publish/collect_intent_label.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/ftrack/plugins/publish/collect_intent_label.py b/openpype/modules/ftrack/plugins/publish/collect_intent_label.py index c23722933c..8375fba15e 100644 --- a/openpype/modules/ftrack/plugins/publish/collect_intent_label.py +++ b/openpype/modules/ftrack/plugins/publish/collect_intent_label.py @@ -11,7 +11,7 @@ import six import pyblish.api -class CollectFtrackApi(pyblish.api.ContextPlugin): +class CollectFtrackIntentLabel(pyblish.api.ContextPlugin): """ Collects an ftrack session and the current task id. """ order = pyblish.api.CollectorOrder + 0.49991 From acba6e8bb08913906209946970f86359a37ca1e4 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 6 Apr 2022 18:52:44 +0200 Subject: [PATCH 46/58] fix import of get_representation_context --- openpype/hosts/tvpaint/plugins/load/load_reference_image.py | 2 +- openpype/pipeline/__init__.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/tvpaint/plugins/load/load_reference_image.py b/openpype/hosts/tvpaint/plugins/load/load_reference_image.py index 5e4e3965d2..af1a4a9b6b 100644 --- a/openpype/hosts/tvpaint/plugins/load/load_reference_image.py +++ b/openpype/hosts/tvpaint/plugins/load/load_reference_image.py @@ -1,6 +1,6 @@ import collections import qargparse -from avalon.pipeline import get_representation_context +from openpype.pipeline import get_representation_context from openpype.hosts.tvpaint.api import lib, pipeline, plugin diff --git a/openpype/pipeline/__init__.py b/openpype/pipeline/__init__.py index 8460d20ef1..883713b078 100644 --- a/openpype/pipeline/__init__.py +++ b/openpype/pipeline/__init__.py @@ -41,6 +41,7 @@ from .load import ( loaders_from_representation, get_representation_path, + get_representation_context, get_repres_contexts, ) @@ -113,6 +114,7 @@ __all__ = ( "loaders_from_representation", "get_representation_path", + "get_representation_context", "get_repres_contexts", # --- Publish --- From f9df89dc0d57fed7f1fccc3a8f43fa194ef8b2d6 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 7 Apr 2022 04:49:26 +0200 Subject: [PATCH 47/58] Fix Validate Asset Docs filename and class name --- .../publish/{validate_aseset_docs.py => validate_asset_docs.py} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename openpype/plugins/publish/{validate_aseset_docs.py => validate_asset_docs.py} (94%) diff --git a/openpype/plugins/publish/validate_aseset_docs.py b/openpype/plugins/publish/validate_asset_docs.py similarity index 94% rename from openpype/plugins/publish/validate_aseset_docs.py rename to openpype/plugins/publish/validate_asset_docs.py index eed75cdf8a..ddd579621c 100644 --- a/openpype/plugins/publish/validate_aseset_docs.py +++ b/openpype/plugins/publish/validate_asset_docs.py @@ -2,7 +2,7 @@ import pyblish.api from openpype.pipeline import PublishValidationError -class ValidateContainers(pyblish.api.InstancePlugin): +class ValidateAssetDocs(pyblish.api.InstancePlugin): """Validate existence of asset asset documents on instances. Without asset document it is not possible to publish the instance. From ae57c8619d863589ae1fc365b86adbab0af890bf Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 7 Apr 2022 04:50:32 +0200 Subject: [PATCH 48/58] Fix grammar + typos --- openpype/plugins/publish/validate_asset_docs.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/plugins/publish/validate_asset_docs.py b/openpype/plugins/publish/validate_asset_docs.py index ddd579621c..bc1f9b9e6c 100644 --- a/openpype/plugins/publish/validate_asset_docs.py +++ b/openpype/plugins/publish/validate_asset_docs.py @@ -3,7 +3,7 @@ from openpype.pipeline import PublishValidationError class ValidateAssetDocs(pyblish.api.InstancePlugin): - """Validate existence of asset asset documents on instances. + """Validate existence of asset documents on instances. Without asset document it is not possible to publish the instance. @@ -22,10 +22,10 @@ class ValidateAssetDocs(pyblish.api.InstancePlugin): return if instance.data.get("assetEntity"): - self.log.info("Instance have set asset document in it's data.") + self.log.info("Instance has set asset document in its data.") else: raise PublishValidationError(( - "Instance \"{}\" don't have set asset" - " document which is needed for publishing." + "Instance \"{}\" doesn't have asset document " + "set which is needed for publishing." ).format(instance.data["name"])) From 31683fb432b885add58e90883f23a4b82a989428 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 7 Apr 2022 05:17:59 +0200 Subject: [PATCH 49/58] Allow to select invalid camera contents if no cameras found + improve error logging --- .../maya/plugins/publish/validate_camera_contents.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_camera_contents.py b/openpype/hosts/maya/plugins/publish/validate_camera_contents.py index d9e88edaac..20af8d2315 100644 --- a/openpype/hosts/maya/plugins/publish/validate_camera_contents.py +++ b/openpype/hosts/maya/plugins/publish/validate_camera_contents.py @@ -40,7 +40,14 @@ class ValidateCameraContents(pyblish.api.InstancePlugin): # list when there are no actual cameras results in # still an empty 'invalid' list if len(cameras) < 1: - raise RuntimeError("No cameras in instance.") + if members: + # If there are members in the instance return all of + # them as 'invalid' so the user can still select invalid + cls.log.error("No cameras found in instance " + "members: {}".format(members)) + return members + + raise RuntimeError("No cameras found in empty instance.") # non-camera shapes valid_shapes = cmds.ls(shapes, type=('camera', 'locator'), long=True) From c298e06ba621162e204299ff849786614d0c02be Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 7 Apr 2022 11:11:46 +0200 Subject: [PATCH 50/58] use 'filepath_from_context' instead of 'get_representation_path_from_context' --- openpype/hosts/maya/plugins/inventory/import_modelrender.py | 5 ++--- .../hosts/photoshop/plugins/load/load_image_from_sequence.py | 3 +-- openpype/pipeline/load/plugins.py | 3 ++- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/maya/plugins/inventory/import_modelrender.py b/openpype/hosts/maya/plugins/inventory/import_modelrender.py index d9bb256fac..c2e43f196f 100644 --- a/openpype/hosts/maya/plugins/inventory/import_modelrender.py +++ b/openpype/hosts/maya/plugins/inventory/import_modelrender.py @@ -4,7 +4,6 @@ from bson.objectid import ObjectId from openpype.pipeline import ( InventoryAction, get_representation_context, - get_representation_path_from_context, ) from openpype.hosts.maya.api.lib import ( maintained_selection, @@ -80,10 +79,10 @@ class ImportModelRender(InventoryAction): }) context = get_representation_context(look_repr["_id"]) - maya_file = get_representation_path_from_context(context) + maya_file = self.filepath_from_context(context) context = get_representation_context(json_repr["_id"]) - json_file = get_representation_path_from_context(context) + json_file = self.filepath_from_context(context) # Import the look file with maintained_selection(): diff --git a/openpype/hosts/photoshop/plugins/load/load_image_from_sequence.py b/openpype/hosts/photoshop/plugins/load/load_image_from_sequence.py index 5f39121ae1..c25c5a8f2c 100644 --- a/openpype/hosts/photoshop/plugins/load/load_image_from_sequence.py +++ b/openpype/hosts/photoshop/plugins/load/load_image_from_sequence.py @@ -2,7 +2,6 @@ import os import qargparse -from openpype.pipeline import get_representation_path_from_context from openpype.hosts.photoshop import api as photoshop from openpype.hosts.photoshop.api import get_unique_layer_name @@ -63,7 +62,7 @@ class ImageFromSequenceLoader(photoshop.PhotoshopLoader): """ files = [] for context in repre_contexts: - fname = get_representation_path_from_context(context) + fname = cls.filepath_from_context(context) _, file_extension = os.path.splitext(fname) for file_name in os.listdir(os.path.dirname(fname)): diff --git a/openpype/pipeline/load/plugins.py b/openpype/pipeline/load/plugins.py index d60aed0083..a30a2188a4 100644 --- a/openpype/pipeline/load/plugins.py +++ b/openpype/pipeline/load/plugins.py @@ -41,7 +41,8 @@ class LoaderPlugin(list): def get_representations(cls): return cls.representations - def filepath_from_context(self, context): + @classmethod + def filepath_from_context(cls, context): return get_representation_path_from_context(context) def load(self, context, name=None, namespace=None, options=None): From cb3722552c4e2875365f237c36aee702af3bf39f Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 7 Apr 2022 11:57:33 +0200 Subject: [PATCH 51/58] removed ftrackIntentLabel --- .../plugins/publish/collect_intent_label.py | 78 ------------------- .../publish/integrate_ftrack_description.py | 12 ++- .../plugins/publish/integrate_ftrack_note.py | 12 ++- 3 files changed, 20 insertions(+), 82 deletions(-) delete mode 100644 openpype/modules/ftrack/plugins/publish/collect_intent_label.py diff --git a/openpype/modules/ftrack/plugins/publish/collect_intent_label.py b/openpype/modules/ftrack/plugins/publish/collect_intent_label.py deleted file mode 100644 index 8375fba15e..0000000000 --- a/openpype/modules/ftrack/plugins/publish/collect_intent_label.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -Requires: - context -> ftrackSession - connected ftrack.Session - -Provides: - context -> ftrackIntentLabel -""" -import json - -import six -import pyblish.api - - -class CollectFtrackIntentLabel(pyblish.api.ContextPlugin): - """ Collects an ftrack session and the current task id. """ - - order = pyblish.api.CollectorOrder + 0.49991 - label = "Collect Ftrack Intent Label" - - def process(self, context): - intent = context.data.get("intent") - if intent and isinstance(intent, dict): - intent_val = intent.get("value") - intent_label = intent.get("label") - else: - intent_val = intent_label = intent - - session = context.data.get("ftrackSession") - if session is None: - context.data["ftrackIntentLabel"] = intent_label - self.log.info("Ftrack session is not available. Skipping.") - return - - final_intent_label = None - if intent_val: - final_intent_label = self.get_intent_label(session, intent_val) - - if final_intent_label is None: - final_intent_label = intent_label - - context.data["ftrackIntentLabel"] = final_intent_label - - def get_intent_label(self, session, intent_value): - if not intent_value: - return - - intent_configurations = session.query( - "CustomAttributeConfiguration where key is intent" - ).all() - if not intent_configurations: - return - - intent_configuration = intent_configurations[0] - if len(intent_configuration) > 1: - self.log.warning(( - "Found more than one `intent` custom attribute." - " Using first found." - )) - - config = intent_configuration.get("config") - if not config: - return - - configuration = json.loads(config) - items = configuration.get("data") - if not items: - return - - if isinstance(items, six.string_types): - items = json.loads(items) - - intent_label = None - for item in items: - if item["value"] == intent_value: - intent_label = item["menu"] - break - - return intent_label diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_description.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_description.py index 7e8371cd9d..c6a3d47f66 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_description.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_description.py @@ -2,7 +2,6 @@ Requires: context > comment context > ftrackSession - context > ftrackIntentLabel instance > ftrackIntegratedAssetVersionsData """ @@ -41,7 +40,16 @@ class IntegrateFtrackDescription(pyblish.api.InstancePlugin): session = instance.context.data["ftrackSession"] - intent_label = instance.context.data["ftrackIntentLabel"] + intent = instance.context.data.get("intent") + intent_label = None + if intent and isinstance(intent, dict): + intent_val = intent.get("value") + intent_label = intent.get("label") + else: + intent_val = intent + + if not intent_label: + intent_label = intent_val or "" # if intent label is set then format comment # - it is possible that intent_label is equal to "" (empty string) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py index 2fe97dc7ac..952b21546d 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_note.py @@ -5,7 +5,6 @@ Requires: context > appLabel context > comment context > ftrackSession - context > ftrackIntentLabel instance > ftrackIntegratedAssetVersionsData """ @@ -52,7 +51,16 @@ class IntegrateFtrackNote(pyblish.api.InstancePlugin): session = context.data["ftrackSession"] - intent_label = context.data["ftrackIntentLabel"] + intent = instance.context.data.get("intent") + intent_label = None + if intent and isinstance(intent, dict): + intent_val = intent.get("value") + intent_label = intent.get("label") + else: + intent_val = intent + + if not intent_label: + intent_label = intent_val or "" # if intent label is set then format comment # - it is possible that intent_label is equal to "" (empty string) From 1c6164005c89e8cf26a15e642c991a40a1261e9c Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 7 Apr 2022 13:24:43 +0200 Subject: [PATCH 52/58] wrapper around settings content is splitter so projects view can be resized --- openpype/tools/settings/settings/categories.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/openpype/tools/settings/settings/categories.py b/openpype/tools/settings/settings/categories.py index a5b5cd40f0..c8ade5fcdb 100644 --- a/openpype/tools/settings/settings/categories.py +++ b/openpype/tools/settings/settings/categories.py @@ -216,7 +216,7 @@ class SettingsCategoryWidget(QtWidgets.QWidget): def create_ui(self): self.modify_defaults_checkbox = None - conf_wrapper_widget = QtWidgets.QWidget(self) + conf_wrapper_widget = QtWidgets.QSplitter(self) configurations_widget = QtWidgets.QWidget(conf_wrapper_widget) # Breadcrumbs/Path widget @@ -294,10 +294,7 @@ class SettingsCategoryWidget(QtWidgets.QWidget): configurations_layout.addWidget(scroll_widget, 1) - conf_wrapper_layout = QtWidgets.QHBoxLayout(conf_wrapper_widget) - conf_wrapper_layout.setContentsMargins(0, 0, 0, 0) - conf_wrapper_layout.setSpacing(0) - conf_wrapper_layout.addWidget(configurations_widget, 1) + conf_wrapper_widget.addWidget(configurations_widget) main_layout = QtWidgets.QVBoxLayout(self) main_layout.setContentsMargins(0, 0, 0, 0) @@ -327,7 +324,7 @@ class SettingsCategoryWidget(QtWidgets.QWidget): self.breadcrumbs_model = None self.refresh_btn = refresh_btn - self.conf_wrapper_layout = conf_wrapper_layout + self.conf_wrapper_widget = conf_wrapper_widget self.main_layout = main_layout self.ui_tweaks() @@ -818,7 +815,9 @@ class ProjectWidget(SettingsCategoryWidget): project_list_widget = ProjectListWidget(self) - self.conf_wrapper_layout.insertWidget(0, project_list_widget, 0) + self.conf_wrapper_widget.insertWidget(0, project_list_widget) + self.conf_wrapper_widget.setStretchFactor(0, 0) + self.conf_wrapper_widget.setStretchFactor(1, 1) project_list_widget.project_changed.connect(self._on_project_change) project_list_widget.version_change_requested.connect( From c966b96e059e4344027542f5db2d42cc80a39a3c Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 7 Apr 2022 13:29:12 +0200 Subject: [PATCH 53/58] fixed default value of use sequence for review --- .../modules/deadline/plugins/publish/submit_publish_job.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_publish_job.py b/openpype/modules/deadline/plugins/publish/submit_publish_job.py index 921b172f2b..3c4e0d2913 100644 --- a/openpype/modules/deadline/plugins/publish/submit_publish_job.py +++ b/openpype/modules/deadline/plugins/publish/submit_publish_job.py @@ -531,10 +531,7 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): # expected files contains more explicitly and from what # should be review made. # - "review" tag is never added when is set to 'False' - use_sequence_for_review = instance.get( - "useSequenceForReview", True - ) - if use_sequence_for_review: + if instance["useSequenceForReview"]: # if filtered aov name is found in filename, toggle it for # preview video rendering for app in self.aov_filter.keys(): @@ -737,7 +734,7 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): "resolutionHeight": data.get("resolutionHeight", 1080), "multipartExr": data.get("multipartExr", False), "jobBatchName": data.get("jobBatchName", ""), - "useSequenceForReview": data.get("useSequenceForReview") + "useSequenceForReview": data.get("useSequenceForReview", True) } if "prerender" in instance.data["families"]: From 53fba93840cc8af47dad7d274880de83146b558f Mon Sep 17 00:00:00 2001 From: OpenPype Date: Thu, 7 Apr 2022 12:14:49 +0000 Subject: [PATCH 54/58] [Automated] Bump version --- CHANGELOG.md | 51 +++++++++++++++++---------------------------- openpype/version.py | 2 +- pyproject.toml | 2 +- 3 files changed, 21 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a53311d70..e17ab74293 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## [3.9.3-nightly.1](https://github.com/pypeclub/OpenPype/tree/HEAD) +## [3.9.3-nightly.2](https://github.com/pypeclub/OpenPype/tree/HEAD) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.9.2...HEAD) @@ -10,16 +10,28 @@ **🆕 New features** +- Ftrack: Add description integrator [\#3027](https://github.com/pypeclub/OpenPype/pull/3027) - Publishing textures for Unreal [\#2988](https://github.com/pypeclub/OpenPype/pull/2988) -- Maya to Unreal \> Static and Skeletal Meshes [\#2978](https://github.com/pypeclub/OpenPype/pull/2978) +- Maya to Unreal: Static and Skeletal Meshes [\#2978](https://github.com/pypeclub/OpenPype/pull/2978) **🚀 Enhancements** +- Ftrack: Add more options for note text of integrate ftrack note [\#3025](https://github.com/pypeclub/OpenPype/pull/3025) +- Console Interpreter: Changed how console splitter size are reused on show [\#3016](https://github.com/pypeclub/OpenPype/pull/3016) +- Deadline: Use more suitable name for sequence review logic [\#3015](https://github.com/pypeclub/OpenPype/pull/3015) - Nuke: add concurrency attr to deadline job [\#3005](https://github.com/pypeclub/OpenPype/pull/3005) +- Deadline: priority configurable in Maya jobs [\#2995](https://github.com/pypeclub/OpenPype/pull/2995) - Workfiles tool: Save as published workfiles [\#2937](https://github.com/pypeclub/OpenPype/pull/2937) **🐛 Bug fixes** +- Deadline: Fixed default value of use sequence for review [\#3033](https://github.com/pypeclub/OpenPype/pull/3033) +- Settings UI: Version column can be extended so version are visible [\#3032](https://github.com/pypeclub/OpenPype/pull/3032) +- General: Fix import after movements [\#3028](https://github.com/pypeclub/OpenPype/pull/3028) +- Harmony: Added creating subset name for workfile from template [\#3024](https://github.com/pypeclub/OpenPype/pull/3024) +- AfterEffects: Added creating subset name for workfile from template [\#3023](https://github.com/pypeclub/OpenPype/pull/3023) +- General: Add example addons to ignored [\#3022](https://github.com/pypeclub/OpenPype/pull/3022) +- Maya: Remove missing import [\#3017](https://github.com/pypeclub/OpenPype/pull/3017) - Ftrack: multiple reviewable componets [\#3012](https://github.com/pypeclub/OpenPype/pull/3012) - Tray publisher: Fixes after code movement [\#3010](https://github.com/pypeclub/OpenPype/pull/3010) - Nuke: fixing unicode type detection in effect loaders [\#3002](https://github.com/pypeclub/OpenPype/pull/3002) @@ -27,6 +39,7 @@ **Merged pull requests:** +- Maya: Allow to select invalid camera contents if no cameras found [\#3030](https://github.com/pypeclub/OpenPype/pull/3030) - General: adding limitations for pyright [\#2994](https://github.com/pypeclub/OpenPype/pull/2994) ## [3.9.2](https://github.com/pypeclub/OpenPype/tree/3.9.2) (2022-04-04) @@ -58,7 +71,8 @@ - Workfiles: Open published workfiles [\#2925](https://github.com/pypeclub/OpenPype/pull/2925) - General: Default modules loaded dynamically [\#2923](https://github.com/pypeclub/OpenPype/pull/2923) - Nuke: Add no-audio Tag [\#2911](https://github.com/pypeclub/OpenPype/pull/2911) -- Flame: support for comment with xml attribute overrides [\#2892](https://github.com/pypeclub/OpenPype/pull/2892) +- Ftrack: Fill workfile in custom attribute [\#2906](https://github.com/pypeclub/OpenPype/pull/2906) +- Nuke: improving readability [\#2903](https://github.com/pypeclub/OpenPype/pull/2903) **🐛 Bug fixes** @@ -92,7 +106,6 @@ - General: Move Attribute Definitions from pipeline [\#2931](https://github.com/pypeclub/OpenPype/pull/2931) - General: Removed silo references and terminal splash [\#2927](https://github.com/pypeclub/OpenPype/pull/2927) - General: Move pipeline constants to OpenPype [\#2918](https://github.com/pypeclub/OpenPype/pull/2918) -- General: Move formatting and workfile functions [\#2914](https://github.com/pypeclub/OpenPype/pull/2914) - General: Move remaining plugins from avalon [\#2912](https://github.com/pypeclub/OpenPype/pull/2912) **Merged pull requests:** @@ -108,11 +121,9 @@ **🚀 Enhancements** -- General: Change how OPENPYPE\_DEBUG value is handled [\#2907](https://github.com/pypeclub/OpenPype/pull/2907) -- Nuke: improving readability [\#2903](https://github.com/pypeclub/OpenPype/pull/2903) +- Settings UI: Add simple tooltips for settings entities [\#2901](https://github.com/pypeclub/OpenPype/pull/2901) - nuke: imageio adding ocio config version 1.2 [\#2897](https://github.com/pypeclub/OpenPype/pull/2897) -- Nuke: ExtractReviewSlate can handle more codes and profiles [\#2879](https://github.com/pypeclub/OpenPype/pull/2879) -- Flame: sequence used for reference video [\#2869](https://github.com/pypeclub/OpenPype/pull/2869) +- Flame: support for comment with xml attribute overrides [\#2892](https://github.com/pypeclub/OpenPype/pull/2892) **🐛 Bug fixes** @@ -121,39 +132,15 @@ - Pyblish Pype - ensure current state is correct when entering new group order [\#2899](https://github.com/pypeclub/OpenPype/pull/2899) - SceneInventory: Fix import of load function [\#2894](https://github.com/pypeclub/OpenPype/pull/2894) - Harmony - fixed creator issue [\#2891](https://github.com/pypeclub/OpenPype/pull/2891) -- General: Remove forgotten use of avalon Creator [\#2885](https://github.com/pypeclub/OpenPype/pull/2885) -- General: Avoid circular import [\#2884](https://github.com/pypeclub/OpenPype/pull/2884) -- Fixes for attaching loaded containers \(\#2837\) [\#2874](https://github.com/pypeclub/OpenPype/pull/2874) **🔀 Refactored code** - General: Reduce style usage to OpenPype repository [\#2889](https://github.com/pypeclub/OpenPype/pull/2889) -- General: Move loader logic from avalon to openpype [\#2886](https://github.com/pypeclub/OpenPype/pull/2886) ## [3.9.0](https://github.com/pypeclub/OpenPype/tree/3.9.0) (2022-03-14) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.9.0-nightly.9...3.9.0) -### 📖 Documentation - -- Documentation: Change Photoshop & AfterEffects plugin path [\#2878](https://github.com/pypeclub/OpenPype/pull/2878) - -**🚀 Enhancements** - -- General: Subset name filtering in ExtractReview outpus [\#2872](https://github.com/pypeclub/OpenPype/pull/2872) -- NewPublisher: Descriptions and Icons in creator dialog [\#2867](https://github.com/pypeclub/OpenPype/pull/2867) - -**🐛 Bug fixes** - -- General: Missing time function [\#2877](https://github.com/pypeclub/OpenPype/pull/2877) -- Deadline: Fix plugin name for tile assemble [\#2868](https://github.com/pypeclub/OpenPype/pull/2868) -- Nuke: gizmo precollect fix [\#2866](https://github.com/pypeclub/OpenPype/pull/2866) -- General: Fix hardlink for windows [\#2864](https://github.com/pypeclub/OpenPype/pull/2864) - -**🔀 Refactored code** - -- Refactor: move webserver tool to openpype [\#2876](https://github.com/pypeclub/OpenPype/pull/2876) - ## [3.8.2](https://github.com/pypeclub/OpenPype/tree/3.8.2) (2022-02-07) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.8.2-nightly.3...3.8.2) diff --git a/openpype/version.py b/openpype/version.py index c314151e9b..1dbbab64de 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.9.3-nightly.1" +__version__ = "3.9.3-nightly.2" diff --git a/pyproject.toml b/pyproject.toml index dd1a666dea..aa00f4022f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.9.3-nightly.1" # OpenPype +version = "3.9.3-nightly.2" # OpenPype description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" From 616d0cf6208ce1be4134b63a9a6722b30bca8252 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Thu, 7 Apr 2022 12:23:14 +0000 Subject: [PATCH 55/58] [Automated] Release --- CHANGELOG.md | 9 ++++----- openpype/version.py | 2 +- pyproject.toml | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e17ab74293..f1e7d5d9e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -## [3.9.3-nightly.2](https://github.com/pypeclub/OpenPype/tree/HEAD) +## [3.9.3](https://github.com/pypeclub/OpenPype/tree/3.9.3) (2022-04-07) -[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.9.2...HEAD) +[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.9.2...3.9.3) ### 📖 Documentation @@ -20,6 +20,7 @@ - Console Interpreter: Changed how console splitter size are reused on show [\#3016](https://github.com/pypeclub/OpenPype/pull/3016) - Deadline: Use more suitable name for sequence review logic [\#3015](https://github.com/pypeclub/OpenPype/pull/3015) - Nuke: add concurrency attr to deadline job [\#3005](https://github.com/pypeclub/OpenPype/pull/3005) +- Photoshop: create image without instance [\#3001](https://github.com/pypeclub/OpenPype/pull/3001) - Deadline: priority configurable in Maya jobs [\#2995](https://github.com/pypeclub/OpenPype/pull/2995) - Workfiles tool: Save as published workfiles [\#2937](https://github.com/pypeclub/OpenPype/pull/2937) @@ -59,7 +60,6 @@ **🚀 Enhancements** -- Photoshop: create image without instance [\#3001](https://github.com/pypeclub/OpenPype/pull/3001) - TVPaint: Render scene family [\#3000](https://github.com/pypeclub/OpenPype/pull/3000) - Nuke: ReviewDataMov Read RAW attribute [\#2985](https://github.com/pypeclub/OpenPype/pull/2985) - General: `METADATA\_KEYS` constant as `frozenset` for optimal immutable lookup [\#2980](https://github.com/pypeclub/OpenPype/pull/2980) @@ -71,7 +71,6 @@ - Workfiles: Open published workfiles [\#2925](https://github.com/pypeclub/OpenPype/pull/2925) - General: Default modules loaded dynamically [\#2923](https://github.com/pypeclub/OpenPype/pull/2923) - Nuke: Add no-audio Tag [\#2911](https://github.com/pypeclub/OpenPype/pull/2911) -- Ftrack: Fill workfile in custom attribute [\#2906](https://github.com/pypeclub/OpenPype/pull/2906) - Nuke: improving readability [\#2903](https://github.com/pypeclub/OpenPype/pull/2903) **🐛 Bug fixes** @@ -121,7 +120,7 @@ **🚀 Enhancements** -- Settings UI: Add simple tooltips for settings entities [\#2901](https://github.com/pypeclub/OpenPype/pull/2901) +- General: Change how OPENPYPE\_DEBUG value is handled [\#2907](https://github.com/pypeclub/OpenPype/pull/2907) - nuke: imageio adding ocio config version 1.2 [\#2897](https://github.com/pypeclub/OpenPype/pull/2897) - Flame: support for comment with xml attribute overrides [\#2892](https://github.com/pypeclub/OpenPype/pull/2892) diff --git a/openpype/version.py b/openpype/version.py index 1dbbab64de..97aa585ca7 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.9.3-nightly.2" +__version__ = "3.9.3" diff --git a/pyproject.toml b/pyproject.toml index aa00f4022f..006f6eb4e5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.9.3-nightly.2" # OpenPype +version = "3.9.3" # OpenPype description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" From 208a6b0ecae86bca96dad9fc0984df16f3b86d7a Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 7 Apr 2022 17:08:16 +0200 Subject: [PATCH 56/58] Fix Python requirements to 3.7.9 According to some cases on Discord, 3.7.8 is not enough with PySide2 combination --- website/docs/dev_requirements.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/dev_requirements.md b/website/docs/dev_requirements.md index 6c87054ba0..a10aea7865 100644 --- a/website/docs/dev_requirements.md +++ b/website/docs/dev_requirements.md @@ -14,7 +14,7 @@ The main things you will need to run and build pype are: - **Terminal** in your OS - PowerShell 5.0+ (Windows) - Bash (Linux) -- [**Python 3.7.8**](#python) or higher +- [**Python 3.7.9**](#python) or higher - [**MongoDB**](#database) From 753ee312a1f36985603e57b3488bd62cff15ad41 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 8 Apr 2022 11:52:10 +0200 Subject: [PATCH 57/58] fixed imports in unreal creators --- openpype/hosts/unreal/plugins/create/create_camera.py | 8 +++----- openpype/hosts/unreal/plugins/create/create_layout.py | 8 +++----- openpype/hosts/unreal/plugins/create/create_look.py | 5 ++--- .../hosts/unreal/plugins/create/create_staticmeshfbx.py | 4 ++-- 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/openpype/hosts/unreal/plugins/create/create_camera.py b/openpype/hosts/unreal/plugins/create/create_camera.py index c2905fb6dd..2842900834 100644 --- a/openpype/hosts/unreal/plugins/create/create_camera.py +++ b/openpype/hosts/unreal/plugins/create/create_camera.py @@ -2,13 +2,11 @@ import unreal from unreal import EditorAssetLibrary as eal from unreal import EditorLevelLibrary as ell -from openpype.hosts.unreal.api.plugin import Creator -from avalon.unreal import ( - instantiate, -) +from openpype.hosts.unreal.api import plugin +from openpype.hosts.unreal.api.pipeline import instantiate -class CreateCamera(Creator): +class CreateCamera(plugin.Creator): """Layout output for character rigs""" name = "layoutMain" diff --git a/openpype/hosts/unreal/plugins/create/create_layout.py b/openpype/hosts/unreal/plugins/create/create_layout.py index 00e83cf433..751bece167 100644 --- a/openpype/hosts/unreal/plugins/create/create_layout.py +++ b/openpype/hosts/unreal/plugins/create/create_layout.py @@ -1,12 +1,10 @@ # -*- coding: utf-8 -*- from unreal import EditorLevelLibrary as ell -from openpype.hosts.unreal.api.plugin import Creator -from avalon.unreal import ( - instantiate, -) +from openpype.hosts.unreal.api import plugin +from openpype.hosts.unreal.api.pipeline import instantiate -class CreateLayout(Creator): +class CreateLayout(plugin.Creator): """Layout output for character rigs.""" name = "layoutMain" diff --git a/openpype/hosts/unreal/plugins/create/create_look.py b/openpype/hosts/unreal/plugins/create/create_look.py index 59c40d3e74..12f6b70ae6 100644 --- a/openpype/hosts/unreal/plugins/create/create_look.py +++ b/openpype/hosts/unreal/plugins/create/create_look.py @@ -1,11 +1,10 @@ # -*- coding: utf-8 -*- """Create look in Unreal.""" import unreal # noqa -from openpype.hosts.unreal.api.plugin import Creator -from openpype.hosts.unreal.api import pipeline +from openpype.hosts.unreal.api import pipeline, plugin -class CreateLook(Creator): +class CreateLook(plugin.Creator): """Shader connections defining shape look.""" name = "unrealLook" diff --git a/openpype/hosts/unreal/plugins/create/create_staticmeshfbx.py b/openpype/hosts/unreal/plugins/create/create_staticmeshfbx.py index 700eac7366..601c2fae06 100644 --- a/openpype/hosts/unreal/plugins/create/create_staticmeshfbx.py +++ b/openpype/hosts/unreal/plugins/create/create_staticmeshfbx.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- """Create Static Meshes as FBX geometry.""" import unreal # noqa -from openpype.hosts.unreal.api.plugin import Creator +from openpype.hosts.unreal.api import plugin from openpype.hosts.unreal.api.pipeline import ( instantiate, ) -class CreateStaticMeshFBX(Creator): +class CreateStaticMeshFBX(plugin.Creator): """Static FBX geometry.""" name = "unrealStaticMeshMain" From 08e7d47cf80bddee85623f36e425114b23a02e38 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 8 Apr 2022 11:52:23 +0200 Subject: [PATCH 58/58] removed unused creator in pipeline.py --- openpype/hosts/unreal/api/pipeline.py | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/openpype/hosts/unreal/api/pipeline.py b/openpype/hosts/unreal/api/pipeline.py index 6d7a6ad1e2..f2c264e5a4 100644 --- a/openpype/hosts/unreal/api/pipeline.py +++ b/openpype/hosts/unreal/api/pipeline.py @@ -4,7 +4,6 @@ import logging from typing import List import pyblish.api -from avalon import api from openpype.pipeline import ( register_loader_plugin_path, @@ -76,30 +75,6 @@ def _register_events(): pass -class Creator(LegacyCreator): - hosts = ["unreal"] - asset_types = [] - - def process(self): - nodes = list() - - with unreal.ScopedEditorTransaction("OpenPype Creating Instance"): - if (self.options or {}).get("useSelection"): - self.log.info("setting ...") - print("settings ...") - nodes = unreal.EditorUtilityLibrary.get_selected_assets() - - asset_paths = [a.get_path_name() for a in nodes] - self.name = move_assets_to_path( - "/Game", self.name, asset_paths - ) - - instance = create_publish_instance("/Game", self.name) - imprint(instance, self.data) - - return instance - - def ls(): """List all containers.