From c2a1017c1da5875967dd51f8596cbab9336954f3 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 27 Apr 2021 17:02:12 +0200 Subject: [PATCH 01/11] PS - all published instances could be grouped with a task name Subset in a group will show up together in Loader --- .../hosts/photoshop/plugins/publish/collect_instances.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/openpype/hosts/photoshop/plugins/publish/collect_instances.py b/openpype/hosts/photoshop/plugins/publish/collect_instances.py index 5390df768b..6acf961d7d 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_instances.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_instances.py @@ -1,3 +1,4 @@ +import os import pyblish.api from avalon import photoshop @@ -19,6 +20,8 @@ class CollectInstances(pyblish.api.ContextPlugin): families_mapping = { "image": [] } + # True will add all instances to same group in Loader + group_by_task_name = False def process(self, context): stub = photoshop.stub() @@ -49,6 +52,12 @@ class CollectInstances(pyblish.api.ContextPlugin): layer_data["family"] ] instance.data["publish"] = layer.visible + + if self.group_by_task_name: + task = os.getenv("AVALON_TASK", None) + sanitized_task_name = task[0].upper() + task[1:] + instance.data["subsetGroup"] = sanitized_task_name + instance_names.append(layer_data["subset"]) # Produce diagnostic message for any graphical From c9006c3f819de8afa89121e34a89980a0ecb0d9c Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 27 Apr 2021 17:07:42 +0200 Subject: [PATCH 02/11] PS - task name pulled from avalon.api instead of env --- openpype/hosts/photoshop/plugins/publish/collect_instances.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/publish/collect_instances.py b/openpype/hosts/photoshop/plugins/publish/collect_instances.py index 6acf961d7d..37d0592d51 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_instances.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_instances.py @@ -1,5 +1,5 @@ -import os import pyblish.api +import avalon.api from avalon import photoshop @@ -54,7 +54,7 @@ class CollectInstances(pyblish.api.ContextPlugin): instance.data["publish"] = layer.visible if self.group_by_task_name: - task = os.getenv("AVALON_TASK", None) + task = avalon.api.Session["AVALON_TASK"] sanitized_task_name = task[0].upper() + task[1:] instance.data["subsetGroup"] = sanitized_task_name From 0f57e21f8b0812237a45554fb797110811a155a6 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 29 Apr 2021 15:23:09 +0200 Subject: [PATCH 03/11] PS subset grouping - added to schema and defaults --- .../defaults/project_settings/global.json | 10 ++++- .../schemas/schema_global_publish.json | 37 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/openpype/settings/defaults/project_settings/global.json b/openpype/settings/defaults/project_settings/global.json index 61db35ba79..ec67ca1654 100644 --- a/openpype/settings/defaults/project_settings/global.json +++ b/openpype/settings/defaults/project_settings/global.json @@ -109,7 +109,15 @@ "prerender" ] } - } + }, + "subset_grouping_profiles": [ + { + "families": [], + "hosts": ["photoshop"], + "tasks": [], + "template": "{Task}" + } + ] }, "ProcessSubmittedJobOnFarm": { "enabled": true, diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json index 1bd028ac79..2150ee57f2 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json @@ -416,6 +416,43 @@ "type": "raw-json", "key": "template_name_profiles", "label": "template_name_profiles" + }, + { + "type": "list", + "key": "subset_grouping_profiles", + "label": "Subset grouping profiles", + "use_label_wrap": true, + "object_type": { + "type": "dict", + "children": [ + { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + }, + { + "key": "hosts", + "label": "Hosts", + "type": "list", + "object_type": "text" + }, + { + "key": "tasks", + "label": "Task names", + "type": "list", + "object_type": "text" + }, + { + "type": "separator" + }, + { + "type": "text", + "key": "template", + "label": "Template" + } + ] + } } ] }, From f75fd3c139ca9de007e81863b2f6711fac4bc6ff Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 29 Apr 2021 17:24:22 +0200 Subject: [PATCH 04/11] PS subset grouping - added resolving subsetGroup from Setting's profiles --- openpype/plugins/publish/integrate_new.py | 66 ++++++++++++++++++++--- 1 file changed, 58 insertions(+), 8 deletions(-) diff --git a/openpype/plugins/publish/integrate_new.py b/openpype/plugins/publish/integrate_new.py index ab9b85983b..a05811b0a6 100644 --- a/openpype/plugins/publish/integrate_new.py +++ b/openpype/plugins/publish/integrate_new.py @@ -16,6 +16,7 @@ from avalon.vendor import filelink import openpype.api from datetime import datetime # from pype.modules import ModulesManager +from openpype.lib.profiles_filtering import filter_profiles # this is needed until speedcopy for linux is fixed if sys.platform == "win32": @@ -697,14 +698,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): subset = io.find_one({"_id": _id}) - # add group if available - if instance.data.get("subsetGroup"): - io.update_many({ - 'type': 'subset', - '_id': io.ObjectId(subset["_id"]) - }, {'$set': {'data.subsetGroup': - instance.data.get('subsetGroup')}} - ) + self._set_subset_group(instance, subset["_id"]) # Update families on subset. families = [instance.data["family"]] @@ -716,6 +710,62 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): return subset + def _set_subset_group(self, instance, subset_id): + """ + Mark subset as belonging to group in DB. + + Uses Settings > Global > Publish plugins > IntegrateAssetNew + + Args: + instance (dict): processed instance + subset_id (str): DB's subset _id + + """ + # add group if available + integrate_new_sett = (instance.context.data["project_settings"] + ["global"] + ["publish"] + ["IntegrateAssetNew"]) + + profiles = integrate_new_sett["subset_grouping_profiles"] + + filtering_criteria = { + "families": instance.data["anatomyData"]["family"], + "hosts": instance.data["anatomyData"]["app"], + "tasks": instance.data["anatomyData"]["task"] or + io.Session["AVALON_TASK"] + } + matching_profile = filter_profiles(profiles, filtering_criteria) + + filled_template = None + fill_pairs = None + if matching_profile: + template = matching_profile["template"] + fill_pairs = { + "family": filtering_criteria["families"], + "task": filtering_criteria["tasks"], + "Family": filtering_criteria["families"].capitalize(), + "Task": filtering_criteria["tasks"].capitalize() + } + filled_template = template.format(**fill_pairs) + + if instance.data.get("subsetGroup") or filled_template: + subset_group = instance.data.get('subsetGroup') or filled_template + + if '{' in subset_group: # some unfilled keys + keys = [] + if fill_pairs: + keys = [item[0] for item in fill_pairs] + msg = "Subset grouping failed. " \ + "Only {} are expected in Settings".format(','.join(keys)) + raise ValueError(msg) + + io.update_many({ + 'type': 'subset', + '_id': io.ObjectId(subset_id) + }, {'$set': {'data.subsetGroup': subset_group}} + ) + def create_version(self, subset, version_number, data=None): """ Copy given source to destination From 47cec33e62508b7e41961c2a4dd5c22c8d28ef28 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 29 Apr 2021 17:26:23 +0200 Subject: [PATCH 05/11] PS subset grouping - reverted back implementation in collect_instances.py --- .../hosts/photoshop/plugins/publish/collect_instances.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/publish/collect_instances.py b/openpype/hosts/photoshop/plugins/publish/collect_instances.py index 37d0592d51..5390df768b 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_instances.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_instances.py @@ -1,5 +1,4 @@ import pyblish.api -import avalon.api from avalon import photoshop @@ -20,8 +19,6 @@ class CollectInstances(pyblish.api.ContextPlugin): families_mapping = { "image": [] } - # True will add all instances to same group in Loader - group_by_task_name = False def process(self, context): stub = photoshop.stub() @@ -52,12 +49,6 @@ class CollectInstances(pyblish.api.ContextPlugin): layer_data["family"] ] instance.data["publish"] = layer.visible - - if self.group_by_task_name: - task = avalon.api.Session["AVALON_TASK"] - sanitized_task_name = task[0].upper() + task[1:] - instance.data["subsetGroup"] = sanitized_task_name - instance_names.append(layer_data["subset"]) # Produce diagnostic message for any graphical From df9b15a59d811656090cb54391a0d612f9e92a3a Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 29 Apr 2021 17:46:36 +0200 Subject: [PATCH 06/11] PS subset grouping - wrong placeholders throw only warning Instance is not marked as in group --- openpype/plugins/publish/integrate_new.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/openpype/plugins/publish/integrate_new.py b/openpype/plugins/publish/integrate_new.py index a05811b0a6..26da19baa2 100644 --- a/openpype/plugins/publish/integrate_new.py +++ b/openpype/plugins/publish/integrate_new.py @@ -747,19 +747,20 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): "Family": filtering_criteria["families"].capitalize(), "Task": filtering_criteria["tasks"].capitalize() } - filled_template = template.format(**fill_pairs) + try: + filled_template = template.format(**fill_pairs) + except KeyError: + keys = [] + if fill_pairs: + keys = fill_pairs.keys() + + msg = "Subset grouping failed. " \ + "Only {} are expected in Settings".format(','.join(keys)) + self.log.warning(msg) if instance.data.get("subsetGroup") or filled_template: subset_group = instance.data.get('subsetGroup') or filled_template - if '{' in subset_group: # some unfilled keys - keys = [] - if fill_pairs: - keys = [item[0] for item in fill_pairs] - msg = "Subset grouping failed. " \ - "Only {} are expected in Settings".format(','.join(keys)) - raise ValueError(msg) - io.update_many({ 'type': 'subset', '_id': io.ObjectId(subset_id) From b7743757ce714aa5188e77a8b6c87d12bd3cd72c Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 29 Apr 2021 17:51:21 +0200 Subject: [PATCH 07/11] PS subset grouping - changed defaults, added label --- openpype/settings/defaults/project_settings/global.json | 4 ++-- .../projects_schema/schemas/schema_global_publish.json | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/openpype/settings/defaults/project_settings/global.json b/openpype/settings/defaults/project_settings/global.json index ec67ca1654..ed61878854 100644 --- a/openpype/settings/defaults/project_settings/global.json +++ b/openpype/settings/defaults/project_settings/global.json @@ -113,9 +113,9 @@ "subset_grouping_profiles": [ { "families": [], - "hosts": ["photoshop"], + "hosts": [], "tasks": [], - "template": "{Task}" + "template": "" } ] }, diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json index 2150ee57f2..5c8b339a1f 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json @@ -425,6 +425,10 @@ "object_type": { "type": "dict", "children": [ + { + "type": "label", + "label": "Set all published instances as a part of specific group named according to 'Template'.
Implemented placeholders [{task},{Task},{family},{Family}]" + }, { "key": "families", "label": "Families", From 53b737949b90ec9a08be3946e8677c3e98c1aeb7 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 29 Apr 2021 17:55:12 +0200 Subject: [PATCH 08/11] Hound --- openpype/plugins/publish/integrate_new.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/openpype/plugins/publish/integrate_new.py b/openpype/plugins/publish/integrate_new.py index 26da19baa2..f74325fe09 100644 --- a/openpype/plugins/publish/integrate_new.py +++ b/openpype/plugins/publish/integrate_new.py @@ -733,7 +733,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): "families": instance.data["anatomyData"]["family"], "hosts": instance.data["anatomyData"]["app"], "tasks": instance.data["anatomyData"]["task"] or - io.Session["AVALON_TASK"] + io.Session["AVALON_TASK"] } matching_profile = filter_profiles(profiles, filtering_criteria) @@ -743,7 +743,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): template = matching_profile["template"] fill_pairs = { "family": filtering_criteria["families"], - "task": filtering_criteria["tasks"], + "task": filtering_criteria["tasks"], "Family": filtering_criteria["families"].capitalize(), "Task": filtering_criteria["tasks"].capitalize() } @@ -762,10 +762,9 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): subset_group = instance.data.get('subsetGroup') or filled_template io.update_many({ - 'type': 'subset', - '_id': io.ObjectId(subset_id) - }, {'$set': {'data.subsetGroup': subset_group}} - ) + 'type': 'subset', + '_id': io.ObjectId(subset_id) + }, {'$set': {'data.subsetGroup': subset_group}}) def create_version(self, subset, version_number, data=None): """ Copy given source to destination From a294665ec63ab19a2be42288aff45f3326bde435 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 29 Apr 2021 19:14:11 +0200 Subject: [PATCH 09/11] SyncServer - handle if globally enabled, but no projects --- .../modules/sync_server/sync_server_module.py | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/openpype/modules/sync_server/sync_server_module.py b/openpype/modules/sync_server/sync_server_module.py index 59c3787789..d8e8b99355 100644 --- a/openpype/modules/sync_server/sync_server_module.py +++ b/openpype/modules/sync_server/sync_server_module.py @@ -401,6 +401,17 @@ class SyncServerModule(PypeModule, ITrayModule): return remote_site + def get_enabled_projects(self): + """Returns list of projects which have SyncServer enabled.""" + enabled_projects = [] + for project in self.connection.projects(): + project_name = project["name"] + project_settings = self.get_sync_project_setting(project_name) + if project_settings: + enabled_projects.append(project_name) + + return enabled_projects + """ End of Public API """ def get_local_file_path(self, collection, site_name, file_path): @@ -413,7 +424,7 @@ class SyncServerModule(PypeModule, ITrayModule): return local_file_path def _get_remote_sites_from_settings(self, sync_settings): - if not self.enabled or not sync_settings['enabled']: + if not self.enabled or not sync_settings.get('enabled'): return [] remote_sites = [self.DEFAULT_SITE, self.LOCAL_SITE] @@ -424,7 +435,7 @@ class SyncServerModule(PypeModule, ITrayModule): def _get_enabled_sites_from_settings(self, sync_settings): sites = [self.DEFAULT_SITE] - if self.enabled and sync_settings['enabled']: + if self.enabled and sync_settings.get('enabled'): sites.append(self.LOCAL_SITE) return sites @@ -445,6 +456,11 @@ class SyncServerModule(PypeModule, ITrayModule): if not self.enabled: return + enabled_projects = self.get_enabled_projects() + if not enabled_projects: + self.enabled = False + return + self.lock = threading.Lock() try: From d92d70a4df50002222a76ff3c5de0425b6a6b9e5 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 29 Apr 2021 19:22:58 +0200 Subject: [PATCH 10/11] Revert "SyncServer - handle if globally enabled, but no projects" This reverts commit a294665ec63ab19a2be42288aff45f3326bde435. --- .../modules/sync_server/sync_server_module.py | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/openpype/modules/sync_server/sync_server_module.py b/openpype/modules/sync_server/sync_server_module.py index d8e8b99355..59c3787789 100644 --- a/openpype/modules/sync_server/sync_server_module.py +++ b/openpype/modules/sync_server/sync_server_module.py @@ -401,17 +401,6 @@ class SyncServerModule(PypeModule, ITrayModule): return remote_site - def get_enabled_projects(self): - """Returns list of projects which have SyncServer enabled.""" - enabled_projects = [] - for project in self.connection.projects(): - project_name = project["name"] - project_settings = self.get_sync_project_setting(project_name) - if project_settings: - enabled_projects.append(project_name) - - return enabled_projects - """ End of Public API """ def get_local_file_path(self, collection, site_name, file_path): @@ -424,7 +413,7 @@ class SyncServerModule(PypeModule, ITrayModule): return local_file_path def _get_remote_sites_from_settings(self, sync_settings): - if not self.enabled or not sync_settings.get('enabled'): + if not self.enabled or not sync_settings['enabled']: return [] remote_sites = [self.DEFAULT_SITE, self.LOCAL_SITE] @@ -435,7 +424,7 @@ class SyncServerModule(PypeModule, ITrayModule): def _get_enabled_sites_from_settings(self, sync_settings): sites = [self.DEFAULT_SITE] - if self.enabled and sync_settings.get('enabled'): + if self.enabled and sync_settings['enabled']: sites.append(self.LOCAL_SITE) return sites @@ -456,11 +445,6 @@ class SyncServerModule(PypeModule, ITrayModule): if not self.enabled: return - enabled_projects = self.get_enabled_projects() - if not enabled_projects: - self.enabled = False - return - self.lock = threading.Lock() try: From 623f19c5fa8b628cfed72a3f34d71ab721a51384 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 4 May 2021 16:03:23 +0200 Subject: [PATCH 11/11] PS subset group - added new standard function Implementation should follow Create subset name approach --- openpype/lib/__init__.py | 1 + openpype/lib/plugin_tools.py | 19 ++++++++++++++- openpype/plugins/publish/integrate_new.py | 23 +++++++++++-------- .../schemas/schema_global_publish.json | 2 +- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/openpype/lib/__init__.py b/openpype/lib/__init__.py index 895d11601f..f0b2db4c1c 100644 --- a/openpype/lib/__init__.py +++ b/openpype/lib/__init__.py @@ -112,6 +112,7 @@ from .profiles_filtering import filter_profiles from .plugin_tools import ( TaskNotSetError, get_subset_name, + prepare_template_data, filter_pyblish_plugins, source_hash, get_unique_layer_name, diff --git a/openpype/lib/plugin_tools.py b/openpype/lib/plugin_tools.py index 9a2d30d1a7..4119ba072a 100644 --- a/openpype/lib/plugin_tools.py +++ b/openpype/lib/plugin_tools.py @@ -73,6 +73,23 @@ def get_subset_name( ("family", family), ("task", task_name) ) + return template.format(**prepare_template_data(fill_pairs)) + + +def prepare_template_data(fill_pairs): + """ + Prepares formatted data for filling template. + + It produces mutliple variants of keys (key, Key, KEY) to control + format of filled template. + + Args: + fill_pairs (iterable) of tuples (key, value) + Returns: + (dict) + ('host', 'maya') > {'host':'maya', 'Host': 'Maya', 'HOST': 'MAYA'} + + """ fill_data = {} for key, value in fill_pairs: # Handle cases when value is `None` (standalone publisher) @@ -94,7 +111,7 @@ def get_subset_name( capitalized += value[1:] fill_data[key.capitalize()] = capitalized - return template.format(**fill_data) + return fill_data def filter_pyblish_plugins(plugins): diff --git a/openpype/plugins/publish/integrate_new.py b/openpype/plugins/publish/integrate_new.py index f74325fe09..19b12e953d 100644 --- a/openpype/plugins/publish/integrate_new.py +++ b/openpype/plugins/publish/integrate_new.py @@ -12,11 +12,13 @@ import shutil from pymongo import DeleteOne, InsertOne import pyblish.api from avalon import io +from avalon.api import format_template_with_optional_keys from avalon.vendor import filelink import openpype.api from datetime import datetime # from pype.modules import ModulesManager from openpype.lib.profiles_filtering import filter_profiles +from openpype.lib import prepare_template_data # this is needed until speedcopy for linux is fixed if sys.platform == "win32": @@ -730,7 +732,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): profiles = integrate_new_sett["subset_grouping_profiles"] filtering_criteria = { - "families": instance.data["anatomyData"]["family"], + "families": instance.data["family"], "hosts": instance.data["anatomyData"]["app"], "tasks": instance.data["anatomyData"]["task"] or io.Session["AVALON_TASK"] @@ -738,17 +740,20 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): matching_profile = filter_profiles(profiles, filtering_criteria) filled_template = None - fill_pairs = None if matching_profile: template = matching_profile["template"] - fill_pairs = { - "family": filtering_criteria["families"], - "task": filtering_criteria["tasks"], - "Family": filtering_criteria["families"].capitalize(), - "Task": filtering_criteria["tasks"].capitalize() - } + fill_pairs = ( + ("family", filtering_criteria["families"]), + ("task", filtering_criteria["tasks"]), + ("host", filtering_criteria["hosts"]), + ("subset", instance.data["subset"]), + ("renderlayer", instance.data.get("renderlayer")) + ) + fill_pairs = prepare_template_data(fill_pairs) + try: - filled_template = template.format(**fill_pairs) + filled_template = \ + format_template_with_optional_keys(fill_pairs, template) except KeyError: keys = [] if fill_pairs: diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json index 5c8b339a1f..581b22545c 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json @@ -427,7 +427,7 @@ "children": [ { "type": "label", - "label": "Set all published instances as a part of specific group named according to 'Template'.
Implemented placeholders [{task},{Task},{family},{Family}]" + "label": "Set all published instances as a part of specific group named according to 'Template'.
Implemented all variants of placeholders [{task},{family},{host},{subset},{renderlayer}]" }, { "key": "families",