From 65b00455614cadd5f279fcfdd37c41f976697c99 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 14 Mar 2022 17:31:57 +0100 Subject: [PATCH 01/32] OP-2766 - fixed not working self.log in New Publisher --- openpype/pipeline/create/creator_plugins.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/pipeline/create/creator_plugins.py b/openpype/pipeline/create/creator_plugins.py index 1ac2c420a2..f05b132fc6 100644 --- a/openpype/pipeline/create/creator_plugins.py +++ b/openpype/pipeline/create/creator_plugins.py @@ -69,7 +69,9 @@ class BaseCreator: @property def log(self): if self._log is None: - self._log = logging.getLogger(self.__class__.__name__) + from openpype.api import Logger + + self._log = Logger.get_logger(self.__class__.__name__) return self._log def _add_instance_to_context(self, instance): From a71dad4608e0be4a91c75769e5edf6722f52f9ff Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 14 Mar 2022 17:35:17 +0100 Subject: [PATCH 02/32] OP-2766 - implemented auto creator for PS Creates workfile instance, updated imprint function. --- openpype/hosts/photoshop/api/pipeline.py | 52 +++++++++---- openpype/hosts/photoshop/api/ws_stub.py | 33 +++++---- .../plugins/create/workfile_creator.py | 73 +++++++++++++++++++ 3 files changed, 131 insertions(+), 27 deletions(-) create mode 100644 openpype/hosts/photoshop/plugins/create/workfile_creator.py diff --git a/openpype/hosts/photoshop/api/pipeline.py b/openpype/hosts/photoshop/api/pipeline.py index 1be8129aa1..0e3f1215aa 100644 --- a/openpype/hosts/photoshop/api/pipeline.py +++ b/openpype/hosts/photoshop/api/pipeline.py @@ -8,7 +8,7 @@ from avalon import pipeline, io from openpype.api import Logger from openpype.lib import register_event_callback -from openpype.pipeline import LegacyCreator +from openpype.pipeline import LegacyCreator, BaseCreator import openpype.hosts.photoshop from . import lib @@ -71,6 +71,7 @@ def install(): pyblish.api.register_plugin_path(PUBLISH_PATH) avalon.api.register_plugin_path(avalon.api.Loader, LOAD_PATH) avalon.api.register_plugin_path(LegacyCreator, CREATE_PATH) + avalon.api.register_plugin_path(BaseCreator, CREATE_PATH) log.info(PUBLISH_PATH) pyblish.api.register_callback( @@ -144,12 +145,9 @@ def list_instances(): layers_meta = stub.get_layers_metadata() if layers_meta: for key, instance in layers_meta.items(): - schema = instance.get("schema") - if schema and "container" in schema: - continue - - instance['uuid'] = key - instances.append(instance) + if instance.get("id") == "pyblish.avalon.instance": # TODO only this way? + instance['uuid'] = key + instances.append(instance) return instances @@ -170,11 +168,18 @@ def remove_instance(instance): if not stub: return - stub.remove_instance(instance.get("uuid")) - layer = stub.get_layer(instance.get("uuid")) - if layer: - stub.rename_layer(instance.get("uuid"), - layer.name.replace(stub.PUBLISH_ICON, '')) + inst_id = instance.get("instance_id") or instance.get("uuid") # legacy + if not inst_id: + log.warning("No instance identifier for {}".format(instance)) + return + + stub.remove_instance(inst_id) + + if instance.get("members"): + item = stub.get_item(instance["members"][0]) + if item: + stub.rename_item(item.id, + item.name.replace(stub.PUBLISH_ICON, '')) def _get_stub(): @@ -226,6 +231,27 @@ def containerise( "members": [str(layer.id)] } stub = lib.stub() - stub.imprint(layer, data) + stub.imprint(layer.id, data) return layer + + +def get_context_data(): + pass + + +def update_context_data(data, changes): + # item = data + # item["id"] = "publish_context" + # _get_stub().imprint(item["id"], item) + pass + + +def get_context_title(): + """Returns title for Creator window""" + import avalon.api + + project_name = avalon.api.Session["AVALON_PROJECT"] + asset_name = avalon.api.Session["AVALON_ASSET"] + task_name = avalon.api.Session["AVALON_TASK"] + return "{}/{}/{}".format(project_name, asset_name, task_name) \ No newline at end of file diff --git a/openpype/hosts/photoshop/api/ws_stub.py b/openpype/hosts/photoshop/api/ws_stub.py index 64d89f5420..a99f184080 100644 --- a/openpype/hosts/photoshop/api/ws_stub.py +++ b/openpype/hosts/photoshop/api/ws_stub.py @@ -27,6 +27,7 @@ class PSItem(object): members = attr.ib(factory=list) long_name = attr.ib(default=None) color_code = attr.ib(default=None) # color code of layer + instance_id = attr.ib(default=None) class PhotoshopServerStub: @@ -82,7 +83,7 @@ class PhotoshopServerStub: return layers_meta.get(str(layer.id)) - def imprint(self, layer, data, all_layers=None, layers_meta=None): + def imprint(self, item_id, data, all_layers=None, items_meta=None): """Save layer metadata to Headline field of active document Stores metadata in format: @@ -108,28 +109,29 @@ class PhotoshopServerStub: }] - for loaded instances Args: - layer (PSItem): + item_id (str): data(string): json representation for single layer all_layers (list of PSItem): for performance, could be injected for usage in loop, if not, single call will be triggered - layers_meta(string): json representation from Headline + items_meta(string): json representation from Headline (for performance - provide only if imprint is in loop - value should be same) Returns: None """ - if not layers_meta: - layers_meta = self.get_layers_metadata() + if not items_meta: + items_meta = self.get_layers_metadata() # json.dumps writes integer values in a dictionary to string, so # anticipating it here. - if str(layer.id) in layers_meta and layers_meta[str(layer.id)]: + item_id = str(item_id) + if item_id in items_meta.keys(): if data: - layers_meta[str(layer.id)].update(data) + items_meta[item_id].update(data) else: - layers_meta.pop(str(layer.id)) + items_meta.pop(item_id) else: - layers_meta[str(layer.id)] = data + items_meta[item_id] = data # Ensure only valid ids are stored. if not all_layers: @@ -137,12 +139,14 @@ class PhotoshopServerStub: layer_ids = [layer.id for layer in all_layers] cleaned_data = [] - for layer_id in layers_meta: - if int(layer_id) in layer_ids: - cleaned_data.append(layers_meta[layer_id]) + for item in items_meta.values(): + if item.get("members"): + if int(item["members"][0]) not in layer_ids: + continue + + cleaned_data.append(item) payload = json.dumps(cleaned_data, indent=4) - self.websocketserver.call( self.client.call('Photoshop.imprint', payload=payload) ) @@ -528,6 +532,7 @@ class PhotoshopServerStub: d.get('type'), d.get('members'), d.get('long_name'), - d.get("color_code") + d.get("color_code"), + d.get("instance_id") )) return ret diff --git a/openpype/hosts/photoshop/plugins/create/workfile_creator.py b/openpype/hosts/photoshop/plugins/create/workfile_creator.py new file mode 100644 index 0000000000..d66a05cad7 --- /dev/null +++ b/openpype/hosts/photoshop/plugins/create/workfile_creator.py @@ -0,0 +1,73 @@ +from avalon import io + +import openpype.hosts.photoshop.api as api +from openpype.pipeline import ( + AutoCreator, + CreatedInstance +) + + +class PSWorkfileCreator(AutoCreator): + identifier = "workfile" + family = "workfile" + + def get_instance_attr_defs(self): + return [] + + def collect_instances(self): + for instance_data in api.list_instances(): + creator_id = instance_data.get("creator_identifier") + if creator_id == self.identifier: + subset_name = instance_data["subset"] + instance = CreatedInstance( + self.family, subset_name, instance_data, self + ) + self._add_instance_to_context(instance) + + def update_instances(self, update_list): + # nothing to change on workfiles + pass + + def create(self, options=None): + existing_instance = None + for instance in self.create_context.instances: + if instance.family == self.family: + existing_instance = instance + break + + variant = '' + project_name = io.Session["AVALON_PROJECT"] + asset_name = io.Session["AVALON_ASSET"] + task_name = io.Session["AVALON_TASK"] + host_name = io.Session["AVALON_APP"] + if existing_instance is None: + asset_doc = io.find_one({"type": "asset", "name": asset_name}) + subset_name = self.get_subset_name( + variant, task_name, asset_doc, project_name, host_name + ) + data = { + "asset": asset_name, + "task": task_name, + "variant": variant + } + data.update(self.get_dynamic_data( + variant, task_name, asset_doc, project_name, host_name + )) + + new_instance = CreatedInstance( + self.family, subset_name, data, self + ) + self._add_instance_to_context(new_instance) + api.stub().imprint(new_instance.get("instance_id"), + new_instance.data_to_store()) + + elif ( + existing_instance["asset"] != asset_name + or existing_instance["task"] != task_name + ): + asset_doc = io.find_one({"type": "asset", "name": asset_name}) + subset_name = self.get_subset_name( + variant, task_name, asset_doc, project_name, host_name + ) + existing_instance["asset"] = asset_name + existing_instance["task"] = task_name From cdb2047ef7e205054f2c31fb6f336e259fa93d47 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 14 Mar 2022 17:35:40 +0100 Subject: [PATCH 03/32] OP-2766 - renamed legacy creator --- .../plugins/create/create_legacy_image.py | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 openpype/hosts/photoshop/plugins/create/create_legacy_image.py diff --git a/openpype/hosts/photoshop/plugins/create/create_legacy_image.py b/openpype/hosts/photoshop/plugins/create/create_legacy_image.py new file mode 100644 index 0000000000..a001b5f171 --- /dev/null +++ b/openpype/hosts/photoshop/plugins/create/create_legacy_image.py @@ -0,0 +1,99 @@ +from Qt import QtWidgets +from openpype.pipeline import create +from openpype.hosts.photoshop import api as photoshop + + +class CreateImage(create.LegacyCreator): + """Image folder for publish.""" + + name = "imageDefault" + label = "Image" + family = "image" + defaults = ["Main"] + + def process(self): + groups = [] + layers = [] + create_group = False + + stub = photoshop.stub() + if (self.options or {}).get("useSelection"): + multiple_instances = False + selection = stub.get_selected_layers() + self.log.info("selection {}".format(selection)) + if len(selection) > 1: + # Ask user whether to create one image or image per selected + # item. + msg_box = QtWidgets.QMessageBox() + msg_box.setIcon(QtWidgets.QMessageBox.Warning) + msg_box.setText( + "Multiple layers selected." + "\nDo you want to make one image per layer?" + ) + msg_box.setStandardButtons( + QtWidgets.QMessageBox.Yes | + QtWidgets.QMessageBox.No | + QtWidgets.QMessageBox.Cancel + ) + ret = msg_box.exec_() + if ret == QtWidgets.QMessageBox.Yes: + multiple_instances = True + elif ret == QtWidgets.QMessageBox.Cancel: + return + + if multiple_instances: + for item in selection: + if item.group: + groups.append(item) + else: + layers.append(item) + else: + group = stub.group_selected_layers(self.name) + groups.append(group) + + elif len(selection) == 1: + # One selected item. Use group if its a LayerSet (group), else + # create a new group. + if selection[0].group: + groups.append(selection[0]) + else: + layers.append(selection[0]) + elif len(selection) == 0: + # No selection creates an empty group. + create_group = True + else: + group = stub.create_group(self.name) + groups.append(group) + + if create_group: + group = stub.create_group(self.name) + groups.append(group) + + for layer in layers: + stub.select_layers([layer]) + group = stub.group_selected_layers(layer.name) + groups.append(group) + + creator_subset_name = self.data["subset"] + for group in groups: + long_names = [] + group.name = group.name.replace(stub.PUBLISH_ICON, ''). \ + replace(stub.LOADED_ICON, '') + + subset_name = creator_subset_name + if len(groups) > 1: + subset_name += group.name.title().replace(" ", "") + + if group.long_name: + for directory in group.long_name[::-1]: + name = directory.replace(stub.PUBLISH_ICON, '').\ + replace(stub.LOADED_ICON, '') + long_names.append(name) + + self.data.update({"subset": subset_name}) + self.data.update({"uuid": str(group.id)}) + self.data.update({"long_name": "_".join(long_names)}) + stub.imprint(group, self.data) + # reusing existing group, need to rename afterwards + if not create_group: + stub.rename_layer(group.id, stub.PUBLISH_ICON + group.name) From bff1b77c0635493c3236f663c7a444eaf2d350e4 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 16 Mar 2022 16:17:46 +0100 Subject: [PATCH 04/32] OP-2766 - changed format of layer metadata Removing uuid, replaced with members[0] and instance_id. Layers metadata now returned as a list, not dictionary to follow AE implementation. --- openpype/hosts/photoshop/api/pipeline.py | 3 +- openpype/hosts/photoshop/api/ws_stub.py | 60 ++++++++++++------------ 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/openpype/hosts/photoshop/api/pipeline.py b/openpype/hosts/photoshop/api/pipeline.py index 0e3f1215aa..8d64942c9e 100644 --- a/openpype/hosts/photoshop/api/pipeline.py +++ b/openpype/hosts/photoshop/api/pipeline.py @@ -144,9 +144,8 @@ def list_instances(): instances = [] layers_meta = stub.get_layers_metadata() if layers_meta: - for key, instance in layers_meta.items(): + for instance in layers_meta: if instance.get("id") == "pyblish.avalon.instance": # TODO only this way? - instance['uuid'] = key instances.append(instance) return instances diff --git a/openpype/hosts/photoshop/api/ws_stub.py b/openpype/hosts/photoshop/api/ws_stub.py index a99f184080..dd29ef4e84 100644 --- a/openpype/hosts/photoshop/api/ws_stub.py +++ b/openpype/hosts/photoshop/api/ws_stub.py @@ -81,7 +81,11 @@ class PhotoshopServerStub: if layers_meta is None: layers_meta = self.get_layers_metadata() - return layers_meta.get(str(layer.id)) + for layer_meta in layers_meta: + if layer_meta.get("members"): + if layer.id == layer_meta["members"][0]: + return layer + print("Unable to find layer metadata for {}".format(layer.id)) def imprint(self, item_id, data, all_layers=None, items_meta=None): """Save layer metadata to Headline field of active document @@ -125,13 +129,21 @@ class PhotoshopServerStub: # json.dumps writes integer values in a dictionary to string, so # anticipating it here. item_id = str(item_id) - if item_id in items_meta.keys(): - if data: - items_meta[item_id].update(data) + is_new = True + result_meta = [] + for item_meta in items_meta: + if ((item_meta.get('members') and + item_id == str(item_meta.get('members')[0])) or + item_meta.get("instance_id") == item_id): + is_new = False + if data: + item_meta.update(data) + result_meta.append(item_meta) else: - items_meta.pop(item_id) - else: - items_meta[item_id] = data + result_meta.append(item_meta) + + if is_new: + result_meta.append(data) # Ensure only valid ids are stored. if not all_layers: @@ -139,7 +151,7 @@ class PhotoshopServerStub: layer_ids = [layer.id for layer in all_layers] cleaned_data = [] - for item in items_meta.values(): + for item in result_meta: if item.get("members"): if int(item["members"][0]) not in layer_ids: continue @@ -374,38 +386,27 @@ class PhotoshopServerStub: (Headline accessible by File > File Info) Returns: - (string): - json documents + (list) example: {"8":{"active":true,"subset":"imageBG", "family":"image","id":"pyblish.avalon.instance", "asset":"Town"}} 8 is layer(group) id - used for deletion, update etc. """ - layers_data = {} res = self.websocketserver.call(self.client.call('Photoshop.read')) + layers_data = [] try: - layers_data = json.loads(res) + if res: + layers_data = json.loads(res) except json.decoder.JSONDecodeError: pass # format of metadata changed from {} to [] because of standardization # keep current implementation logic as its working - if not isinstance(layers_data, dict): - temp_layers_meta = {} - for layer_meta in layers_data: - layer_id = layer_meta.get("uuid") - if not layer_id: - layer_id = layer_meta.get("members")[0] - - temp_layers_meta[layer_id] = layer_meta - layers_data = temp_layers_meta - else: - # legacy version of metadata + if isinstance(layers_data, dict): for layer_id, layer_meta in layers_data.items(): if layer_meta.get("schema") != "openpype:container-2.0": - layer_meta["uuid"] = str(layer_id) - else: layer_meta["members"] = [str(layer_id)] - + layers_data = list(layers_data.values()) return layers_data def import_smart_object(self, path, layer_name, as_reference=False): @@ -476,11 +477,12 @@ class PhotoshopServerStub: ) def remove_instance(self, instance_id): - cleaned_data = {} + cleaned_data = [] - for key, instance in self.get_layers_metadata().items(): - if key != instance_id: - cleaned_data[key] = instance + for item in self.get_layers_metadata(): + inst_id = item.get("instance_id") or item.get("uuid") + if inst_id != instance_id: + cleaned_data.append(inst_id) payload = json.dumps(cleaned_data, indent=4) From c46b41804d108cc976aae64410ce520ac3117dda Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 16 Mar 2022 16:18:07 +0100 Subject: [PATCH 05/32] OP-2766 - implemented new image Creator Working implementation of New Publisher (not full backward compatibility yet). --- openpype/hosts/photoshop/api/__init__.py | 8 +- .../photoshop/plugins/create/create_image.py | 156 ++++++++++++------ .../plugins/create/create_legacy_image.py | 2 +- .../plugins/create/workfile_creator.py | 2 + .../plugins/publish/collect_instances.py | 4 + .../plugins/publish/collect_workfile.py | 30 ++-- .../plugins/publish/extract_image.py | 9 +- 7 files changed, 148 insertions(+), 63 deletions(-) diff --git a/openpype/hosts/photoshop/api/__init__.py b/openpype/hosts/photoshop/api/__init__.py index 17ea957066..94152b5706 100644 --- a/openpype/hosts/photoshop/api/__init__.py +++ b/openpype/hosts/photoshop/api/__init__.py @@ -12,7 +12,10 @@ from .pipeline import ( remove_instance, install, uninstall, - containerise + containerise, + get_context_data, + update_context_data, + get_context_title ) from .plugin import ( PhotoshopLoader, @@ -43,6 +46,9 @@ __all__ = [ "install", "uninstall", "containerise", + "get_context_data", + "update_context_data", + "get_context_title", # Plugin "PhotoshopLoader", diff --git a/openpype/hosts/photoshop/plugins/create/create_image.py b/openpype/hosts/photoshop/plugins/create/create_image.py index a001b5f171..a73b79e0fd 100644 --- a/openpype/hosts/photoshop/plugins/create/create_image.py +++ b/openpype/hosts/photoshop/plugins/create/create_image.py @@ -1,46 +1,50 @@ -from Qt import QtWidgets -from openpype.pipeline import create -from openpype.hosts.photoshop import api as photoshop +from avalon import api as avalon_api +from openpype.hosts.photoshop import api +from openpype.pipeline import ( + Creator, + CreatedInstance, + lib, + CreatorError +) -class CreateImage(create.LegacyCreator): - """Image folder for publish.""" - - name = "imageDefault" +class ImageCreator(Creator): + """Creates image instance for publishing.""" + identifier = "image" label = "Image" family = "image" - defaults = ["Main"] + description = "Image creator" - def process(self): + def collect_instances(self): + import json + self.log.info("ImageCreator: api.list_instances():: {}".format( + json.dumps(api.list_instances(), indent=4))) + for instance_data in api.list_instances(): + # legacy instances have family=='image' + creator_id = (instance_data.get("creator_identifier") or + instance_data.get("family")) + + self.log.info("ImageCreator: instance_data:: {}".format(json.dumps(instance_data, indent=4))) + if creator_id == self.identifier: + instance_data = self._handle_legacy(instance_data) + + layer = api.stub().get_layer(instance_data["members"][0]) + instance_data["layer"] = layer + instance = CreatedInstance.from_existing( + instance_data, self + ) + self._add_instance_to_context(instance) + + def create(self, subset_name, data, pre_create_data): groups = [] layers = [] create_group = False - stub = photoshop.stub() - if (self.options or {}).get("useSelection"): - multiple_instances = False - selection = stub.get_selected_layers() - self.log.info("selection {}".format(selection)) + stub = api.stub() # only after PS is up + multiple_instances = pre_create_data.get("create_multiple") + selection = stub.get_selected_layers() + if pre_create_data.get("use_selection"): if len(selection) > 1: - # Ask user whether to create one image or image per selected - # item. - msg_box = QtWidgets.QMessageBox() - msg_box.setIcon(QtWidgets.QMessageBox.Warning) - msg_box.setText( - "Multiple layers selected." - "\nDo you want to make one image per layer?" - ) - msg_box.setStandardButtons( - QtWidgets.QMessageBox.Yes | - QtWidgets.QMessageBox.No | - QtWidgets.QMessageBox.Cancel - ) - ret = msg_box.exec_() - if ret == QtWidgets.QMessageBox.Yes: - multiple_instances = True - elif ret == QtWidgets.QMessageBox.Cancel: - return - if multiple_instances: for item in selection: if item.group: @@ -48,25 +52,25 @@ class CreateImage(create.LegacyCreator): else: layers.append(item) else: - group = stub.group_selected_layers(self.name) + group = stub.group_selected_layers(subset_name) groups.append(group) - elif len(selection) == 1: # One selected item. Use group if its a LayerSet (group), else # create a new group. - if selection[0].group: - groups.append(selection[0]) + selected_item = selection[0] + if selected_item.group: + groups.append(selected_item) else: - layers.append(selection[0]) + layers.append(selected_item) elif len(selection) == 0: # No selection creates an empty group. create_group = True else: - group = stub.create_group(self.name) + group = stub.create_group(subset_name) groups.append(group) if create_group: - group = stub.create_group(self.name) + group = stub.create_group(subset_name) groups.append(group) for layer in layers: @@ -74,26 +78,78 @@ class CreateImage(create.LegacyCreator): group = stub.group_selected_layers(layer.name) groups.append(group) - creator_subset_name = self.data["subset"] for group in groups: long_names = [] - group.name = group.name.replace(stub.PUBLISH_ICON, ''). \ - replace(stub.LOADED_ICON, '') + group.name = self._clean_highlights(stub, group.name) - subset_name = creator_subset_name if len(groups) > 1: subset_name += group.name.title().replace(" ", "") if group.long_name: for directory in group.long_name[::-1]: - name = directory.replace(stub.PUBLISH_ICON, '').\ - replace(stub.LOADED_ICON, '') + name = self._clean_highlights(stub, directory) long_names.append(name) - self.data.update({"subset": subset_name}) - self.data.update({"uuid": str(group.id)}) - self.data.update({"long_name": "_".join(long_names)}) - stub.imprint(group, self.data) + data.update({"subset": subset_name}) + data.update({"layer": group}) + data.update({"members": [str(group.id)]}) + data.update({"long_name": "_".join(long_names)}) + + new_instance = CreatedInstance(self.family, subset_name, data, + self) + + stub.imprint(new_instance.get("instance_id"), + new_instance.data_to_store()) + self._add_instance_to_context(new_instance) # reusing existing group, need to rename afterwards if not create_group: stub.rename_layer(group.id, stub.PUBLISH_ICON + group.name) + + def update_instances(self, update_list): + self.log.info("update_list:: {}".format(update_list)) + created_inst, changes = update_list[0] + api.stub().imprint(created_inst.get("instance_id"), + created_inst.data_to_store()) + + def remove_instances(self, instances): + for instance in instances: + api.remove_instance(instance) + self._remove_instance_from_context(instance) + + def get_default_variants(self): + return [ + "Main" + ] + + def get_pre_create_attr_defs(self): + output = [ + lib.BoolDef("use_selection", default=True, label="Use selection"), + lib.BoolDef("create_multiple", + default=True, + label="Create separate instance for each selected") + ] + return output + + def get_detail_description(self): + return """Creator for Image instances""" + + def _handle_legacy(self, instance_data): + """Converts old instances to new format.""" + if not instance_data.get("members"): + instance_data["members"] = [instance_data.get("uuid")] + + if instance_data.get("uuid"): + # uuid not needed, replaced with unique instance_id + api.stub().remove_instance(instance_data.get("uuid")) + instance_data.pop("uuid") + + if not instance_data.get("task"): + instance_data["task"] = avalon_api.Session.get("AVALON_TASK") + + return instance_data + + def _clean_highlights(self, stub, item): + return item.replace(stub.PUBLISH_ICON, '').replace(stub.LOADED_ICON, + '') + + diff --git a/openpype/hosts/photoshop/plugins/create/create_legacy_image.py b/openpype/hosts/photoshop/plugins/create/create_legacy_image.py index a001b5f171..6fa455fa03 100644 --- a/openpype/hosts/photoshop/plugins/create/create_legacy_image.py +++ b/openpype/hosts/photoshop/plugins/create/create_legacy_image.py @@ -91,7 +91,7 @@ class CreateImage(create.LegacyCreator): long_names.append(name) self.data.update({"subset": subset_name}) - self.data.update({"uuid": str(group.id)}) + self.data.update({"members": [str(group.id)]}) self.data.update({"long_name": "_".join(long_names)}) stub.imprint(group, self.data) # reusing existing group, need to rename afterwards diff --git a/openpype/hosts/photoshop/plugins/create/workfile_creator.py b/openpype/hosts/photoshop/plugins/create/workfile_creator.py index d66a05cad7..2a2fda3cc4 100644 --- a/openpype/hosts/photoshop/plugins/create/workfile_creator.py +++ b/openpype/hosts/photoshop/plugins/create/workfile_creator.py @@ -15,6 +15,7 @@ class PSWorkfileCreator(AutoCreator): return [] def collect_instances(self): + print("coll::{}".format(api.list_instances())) for instance_data in api.list_instances(): creator_id = instance_data.get("creator_identifier") if creator_id == self.identifier: @@ -29,6 +30,7 @@ class PSWorkfileCreator(AutoCreator): pass def create(self, options=None): + print("create") existing_instance = None for instance in self.create_context.instances: if instance.family == self.family: diff --git a/openpype/hosts/photoshop/plugins/publish/collect_instances.py b/openpype/hosts/photoshop/plugins/publish/collect_instances.py index c3e27e9646..ee402dcabf 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_instances.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_instances.py @@ -21,6 +21,10 @@ class CollectInstances(pyblish.api.ContextPlugin): } def process(self, context): + if context.data.get("newPublishing"): + self.log.debug("Not applicable for New Publisher, skip") + return + stub = photoshop.stub() layers = stub.get_layers() layers_meta = stub.get_layers_metadata() diff --git a/openpype/hosts/photoshop/plugins/publish/collect_workfile.py b/openpype/hosts/photoshop/plugins/publish/collect_workfile.py index db1ede14d5..bdbd379a33 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_workfile.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_workfile.py @@ -10,6 +10,13 @@ class CollectWorkfile(pyblish.api.ContextPlugin): hosts = ["photoshop"] def process(self, context): + existing_instance = None + for instance in context: + if instance.data["family"] == "workfile": + self.log.debug("Workfile instance found, won't create new") + existing_instance = instance + break + family = "workfile" task = os.getenv("AVALON_TASK", None) subset = family + task.capitalize() @@ -19,16 +26,19 @@ class CollectWorkfile(pyblish.api.ContextPlugin): base_name = os.path.basename(file_path) # Create instance - instance = context.create_instance(subset) - instance.data.update({ - "subset": subset, - "label": base_name, - "name": base_name, - "family": family, - "families": [], - "representations": [], - "asset": os.environ["AVALON_ASSET"] - }) + if existing_instance is None: + instance = context.create_instance(subset) + instance.data.update({ + "subset": subset, + "label": base_name, + "name": base_name, + "family": family, + "families": [], + "representations": [], + "asset": os.environ["AVALON_ASSET"] + }) + else: + instance = existing_instance # creating representation _, ext = os.path.splitext(file_path) diff --git a/openpype/hosts/photoshop/plugins/publish/extract_image.py b/openpype/hosts/photoshop/plugins/publish/extract_image.py index 04ce77ee34..d27c5bc028 100644 --- a/openpype/hosts/photoshop/plugins/publish/extract_image.py +++ b/openpype/hosts/photoshop/plugins/publish/extract_image.py @@ -16,7 +16,8 @@ class ExtractImage(openpype.api.Extractor): formats = ["png", "jpg"] def process(self, instance): - + print("PPPPPP") + self.log.info("fdfdsfdfs") staging_dir = self.staging_dir(instance) self.log.info("Outputting image to {}".format(staging_dir)) @@ -26,7 +27,13 @@ class ExtractImage(openpype.api.Extractor): with photoshop.maintained_selection(): self.log.info("Extracting %s" % str(list(instance))) with photoshop.maintained_visibility(): + self.log.info("instance.data:: {}".format(instance.data)) + print("instance.data::: {}".format(instance.data)) layer = instance.data.get("layer") + self.log.info("layer:: {}".format(layer)) + print("layer::: {}".format(layer)) + if not layer: + return ids = set([layer.id]) add_ids = instance.data.pop("ids", None) if add_ids: From a5ac3ab55b2c67604ef8e2530c57bdf242e6c599 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 16 Mar 2022 16:21:29 +0100 Subject: [PATCH 06/32] OP-2766 - implemented new context methods --- openpype/hosts/photoshop/api/pipeline.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/photoshop/api/pipeline.py b/openpype/hosts/photoshop/api/pipeline.py index 8d64942c9e..0a99d1779d 100644 --- a/openpype/hosts/photoshop/api/pipeline.py +++ b/openpype/hosts/photoshop/api/pipeline.py @@ -236,14 +236,21 @@ def containerise( def get_context_data(): - pass + """Get stored values for context (validation enable/disable etc)""" + meta = _get_stub().get_layers_metadata() + for item in meta: + if item.get("id") == "publish_context": + item.pop("id") + return item + + return {} def update_context_data(data, changes): - # item = data - # item["id"] = "publish_context" - # _get_stub().imprint(item["id"], item) - pass + """Store value needed for context""" + item = data + item["id"] = "publish_context" + _get_stub().imprint(item["id"], item) def get_context_title(): From df5fdcc54c6ff125d307036b26a07572671047c9 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 17 Mar 2022 10:45:54 +0100 Subject: [PATCH 07/32] OP-2766 - do not store PSItem in metadata PSItem is not serializable --- openpype/hosts/photoshop/plugins/create/create_image.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hosts/photoshop/plugins/create/create_image.py b/openpype/hosts/photoshop/plugins/create/create_image.py index a73b79e0fd..4fc9a86635 100644 --- a/openpype/hosts/photoshop/plugins/create/create_image.py +++ b/openpype/hosts/photoshop/plugins/create/create_image.py @@ -108,6 +108,7 @@ class ImageCreator(Creator): def update_instances(self, update_list): self.log.info("update_list:: {}".format(update_list)) created_inst, changes = update_list[0] + created_inst.pop("layer") # not storing PSItem layer to metadata api.stub().imprint(created_inst.get("instance_id"), created_inst.data_to_store()) From c422176553ff27cff8d5113958fadf0dc4ddf12e Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 17 Mar 2022 11:29:41 +0100 Subject: [PATCH 08/32] OP-2766 - removed hardcoded ftrack, CollectFtrackFamily should be used Added defaults for Ftrack Settings. --- .../plugins/publish/collect_review.py | 25 +++++++++++++------ .../defaults/project_settings/ftrack.json | 12 +++++++++ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/publish/collect_review.py b/openpype/hosts/photoshop/plugins/publish/collect_review.py index 5ab48b76da..4b6f855a6a 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_review.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_review.py @@ -1,12 +1,24 @@ +""" +Requires: + None + +Provides: + instance -> family ("review") +""" + import os import pyblish.api class CollectReview(pyblish.api.ContextPlugin): - """Gather the active document as review instance.""" + """Gather the active document as review instance. - label = "Review" + Triggers once even if no 'image' is published as by defaults it creates + flatten image from a workfile. + """ + + label = "Collect Review" order = pyblish.api.CollectorOrder hosts = ["photoshop"] @@ -15,16 +27,13 @@ class CollectReview(pyblish.api.ContextPlugin): task = os.getenv("AVALON_TASK", None) subset = family + task.capitalize() - file_path = context.data["currentFile"] - base_name = os.path.basename(file_path) - instance = context.create_instance(subset) instance.data.update({ "subset": subset, - "label": base_name, - "name": base_name, + "label": subset, + "name": subset, "family": family, - "families": ["ftrack"], + "families": [], "representations": [], "asset": os.environ["AVALON_ASSET"] }) diff --git a/openpype/settings/defaults/project_settings/ftrack.json b/openpype/settings/defaults/project_settings/ftrack.json index 01831efad1..015413e64f 100644 --- a/openpype/settings/defaults/project_settings/ftrack.json +++ b/openpype/settings/defaults/project_settings/ftrack.json @@ -344,6 +344,18 @@ "tasks": [], "add_ftrack_family": true, "advanced_filtering": [] + }, + { + "hosts": [ + "photoshop" + ], + "families": [ + "review" + ], + "task_types": [], + "tasks": [], + "add_ftrack_family": true, + "advanced_filtering": [] } ] }, From a6a1d0fc545d8fc5a8781f40468a95a261ca3b01 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 18 Mar 2022 15:22:46 +0100 Subject: [PATCH 09/32] OP-2766 - fixed broken remove_instance --- openpype/hosts/photoshop/api/ws_stub.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/photoshop/api/ws_stub.py b/openpype/hosts/photoshop/api/ws_stub.py index dd29ef4e84..fa076ecc7e 100644 --- a/openpype/hosts/photoshop/api/ws_stub.py +++ b/openpype/hosts/photoshop/api/ws_stub.py @@ -77,14 +77,28 @@ class PhotoshopServerStub: layer: (PSItem) layers_meta: full list from Headline (for performance in loops) Returns: + (dict) of layer metadata stored in PS file + + Example: + { + 'id': 'pyblish.avalon.container', + 'loader': 'ImageLoader', + 'members': ['64'], + 'name': 'imageMainMiddle', + 'namespace': 'Hero_imageMainMiddle_001', + 'representation': '6203dc91e80934d9f6ee7d96', + 'schema': 'openpype:container-2.0' + } """ if layers_meta is None: layers_meta = self.get_layers_metadata() for layer_meta in layers_meta: + layer_id = layer_meta.get("uuid") # legacy if layer_meta.get("members"): - if layer.id == layer_meta["members"][0]: - return layer + layer_id = layer_meta["members"][0] + if str(layer.id) == str(layer_id): + return layer_meta print("Unable to find layer metadata for {}".format(layer.id)) def imprint(self, item_id, data, all_layers=None, items_meta=None): @@ -399,7 +413,7 @@ class PhotoshopServerStub: if res: layers_data = json.loads(res) except json.decoder.JSONDecodeError: - pass + raise ValueError("{} cannot be parsed, recreate meta".format(res)) # format of metadata changed from {} to [] because of standardization # keep current implementation logic as its working if isinstance(layers_data, dict): @@ -482,7 +496,7 @@ class PhotoshopServerStub: for item in self.get_layers_metadata(): inst_id = item.get("instance_id") or item.get("uuid") if inst_id != instance_id: - cleaned_data.append(inst_id) + cleaned_data.append(item) payload = json.dumps(cleaned_data, indent=4) From 01f2c8c1044ddeb78912dc2f6e401a4700e1a67d Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 18 Mar 2022 15:24:51 +0100 Subject: [PATCH 10/32] OP-2766 - fixed layer and variant keys --- .../hosts/photoshop/plugins/create/create_image.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/create/create_image.py b/openpype/hosts/photoshop/plugins/create/create_image.py index 4fc9a86635..c24d8bde2f 100644 --- a/openpype/hosts/photoshop/plugins/create/create_image.py +++ b/openpype/hosts/photoshop/plugins/create/create_image.py @@ -16,18 +16,13 @@ class ImageCreator(Creator): description = "Image creator" def collect_instances(self): - import json - self.log.info("ImageCreator: api.list_instances():: {}".format( - json.dumps(api.list_instances(), indent=4))) for instance_data in api.list_instances(): # legacy instances have family=='image' creator_id = (instance_data.get("creator_identifier") or instance_data.get("family")) - self.log.info("ImageCreator: instance_data:: {}".format(json.dumps(instance_data, indent=4))) if creator_id == self.identifier: instance_data = self._handle_legacy(instance_data) - layer = api.stub().get_layer(instance_data["members"][0]) instance_data["layer"] = layer instance = CreatedInstance.from_existing( @@ -106,9 +101,10 @@ class ImageCreator(Creator): stub.rename_layer(group.id, stub.PUBLISH_ICON + group.name) def update_instances(self, update_list): - self.log.info("update_list:: {}".format(update_list)) + self.log.debug("update_list:: {}".format(update_list)) created_inst, changes = update_list[0] - created_inst.pop("layer") # not storing PSItem layer to metadata + if created_inst.get("layer"): + created_inst.pop("layer") # not storing PSItem layer to metadata api.stub().imprint(created_inst.get("instance_id"), created_inst.data_to_store()) @@ -147,6 +143,9 @@ class ImageCreator(Creator): if not instance_data.get("task"): instance_data["task"] = avalon_api.Session.get("AVALON_TASK") + if not instance_data.get("variant"): + instance_data["variant"] = '' + return instance_data def _clean_highlights(self, stub, item): From 6fde2110148e62649ae3bd0d25726d5dd9c16859 Mon Sep 17 00:00:00 2001 From: Pype Club Date: Tue, 22 Mar 2022 16:37:31 +0100 Subject: [PATCH 11/32] OP-2766 - fix loaders because of change in imprint signature --- openpype/hosts/photoshop/plugins/load/load_image.py | 4 ++-- openpype/hosts/photoshop/plugins/load/load_reference.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/load/load_image.py b/openpype/hosts/photoshop/plugins/load/load_image.py index 0a9421b8f2..91a9787781 100644 --- a/openpype/hosts/photoshop/plugins/load/load_image.py +++ b/openpype/hosts/photoshop/plugins/load/load_image.py @@ -61,7 +61,7 @@ class ImageLoader(photoshop.PhotoshopLoader): ) stub.imprint( - layer, {"representation": str(representation["_id"])} + layer.id, {"representation": str(representation["_id"])} ) def remove(self, container): @@ -73,7 +73,7 @@ class ImageLoader(photoshop.PhotoshopLoader): stub = self.get_stub() layer = container.pop("layer") - stub.imprint(layer, {}) + stub.imprint(layer.id, {}) stub.delete_layer(layer.id) def switch(self, container, representation): diff --git a/openpype/hosts/photoshop/plugins/load/load_reference.py b/openpype/hosts/photoshop/plugins/load/load_reference.py index f5f0545d39..1f32a5d23c 100644 --- a/openpype/hosts/photoshop/plugins/load/load_reference.py +++ b/openpype/hosts/photoshop/plugins/load/load_reference.py @@ -61,7 +61,7 @@ class ReferenceLoader(photoshop.PhotoshopLoader): ) stub.imprint( - layer, {"representation": str(representation["_id"])} + layer.id, {"representation": str(representation["_id"])} ) def remove(self, container): @@ -72,7 +72,7 @@ class ReferenceLoader(photoshop.PhotoshopLoader): """ stub = self.get_stub() layer = container.pop("layer") - stub.imprint(layer, {}) + stub.imprint(layer.id, {}) stub.delete_layer(layer.id) def switch(self, container, representation): From bdc3a05c4d52a29c1aaff99d83c993be48c7563e Mon Sep 17 00:00:00 2001 From: Pype Club Date: Tue, 22 Mar 2022 16:38:46 +0100 Subject: [PATCH 12/32] OP-2766 - fix wrongly used functions --- openpype/hosts/photoshop/api/pipeline.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/photoshop/api/pipeline.py b/openpype/hosts/photoshop/api/pipeline.py index 2f4343753c..abc4e63bf6 100644 --- a/openpype/hosts/photoshop/api/pipeline.py +++ b/openpype/hosts/photoshop/api/pipeline.py @@ -179,10 +179,10 @@ def remove_instance(instance): stub.remove_instance(inst_id) if instance.get("members"): - item = stub.get_item(instance["members"][0]) + item = stub.get_layer(instance["members"][0]) if item: - stub.rename_item(item.id, - item.name.replace(stub.PUBLISH_ICON, '')) + stub.rename_layer(item.id, + item.name.replace(stub.PUBLISH_ICON, '')) def _get_stub(): From b8dd330be3f0de72ba1a28652dff2ae4702c3dc2 Mon Sep 17 00:00:00 2001 From: Pype Club Date: Tue, 22 Mar 2022 16:40:28 +0100 Subject: [PATCH 13/32] OP-2766 - fix new creator for multiple instance's update --- .../hosts/photoshop/plugins/create/create_image.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/create/create_image.py b/openpype/hosts/photoshop/plugins/create/create_image.py index c24d8bde2f..bc0fa6a051 100644 --- a/openpype/hosts/photoshop/plugins/create/create_image.py +++ b/openpype/hosts/photoshop/plugins/create/create_image.py @@ -102,11 +102,11 @@ class ImageCreator(Creator): def update_instances(self, update_list): self.log.debug("update_list:: {}".format(update_list)) - created_inst, changes = update_list[0] - if created_inst.get("layer"): - created_inst.pop("layer") # not storing PSItem layer to metadata - api.stub().imprint(created_inst.get("instance_id"), - created_inst.data_to_store()) + for created_inst, _changes in update_list: + if created_inst.get("layer"): + created_inst.pop("layer") # not storing PSItem layer to metadata + api.stub().imprint(created_inst.get("instance_id"), + created_inst.data_to_store()) def remove_instances(self, instances): for instance in instances: From adc135cb4c1d09eb27d51dae067f054a93c74d77 Mon Sep 17 00:00:00 2001 From: Pype Club Date: Tue, 22 Mar 2022 16:59:53 +0100 Subject: [PATCH 14/32] OP-2766 - added newPublishing flag to differentiate old from new --- openpype/plugins/publish/collect_from_create_context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/plugins/publish/collect_from_create_context.py b/openpype/plugins/publish/collect_from_create_context.py index 16e3f669c3..09584ab37c 100644 --- a/openpype/plugins/publish/collect_from_create_context.py +++ b/openpype/plugins/publish/collect_from_create_context.py @@ -25,7 +25,7 @@ class CollectFromCreateContext(pyblish.api.ContextPlugin): # Update global data to context context.data.update(create_context.context_data_to_store()) - + context.data["newPublishing"] = True # Update context data for key in ("AVALON_PROJECT", "AVALON_ASSET", "AVALON_TASK"): value = create_context.dbcon.Session.get(key) From 96d88e592d56cb5193a13764aba9f5fcecff9616 Mon Sep 17 00:00:00 2001 From: Pype Club Date: Tue, 22 Mar 2022 17:01:35 +0100 Subject: [PATCH 15/32] OP-2766 - renamed collector --- openpype/hosts/photoshop/plugins/publish/collect_instances.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/photoshop/plugins/publish/collect_instances.py b/openpype/hosts/photoshop/plugins/publish/collect_instances.py index ee402dcabf..d506b9a5bf 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_instances.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_instances.py @@ -13,7 +13,7 @@ class CollectInstances(pyblish.api.ContextPlugin): id (str): "pyblish.avalon.instance" """ - label = "Instances" + label = "Collect Instances" order = pyblish.api.CollectorOrder hosts = ["photoshop"] families_mapping = { From e86dc1acd77b841d36486a594862473e6aaf76a8 Mon Sep 17 00:00:00 2001 From: Pype Club Date: Tue, 22 Mar 2022 19:57:02 +0100 Subject: [PATCH 16/32] OP-2766 - refactored new creator --- .../photoshop/plugins/create/create_image.py | 79 ++++++++----------- 1 file changed, 33 insertions(+), 46 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/create/create_image.py b/openpype/hosts/photoshop/plugins/create/create_image.py index bc0fa6a051..cd7e219bd0 100644 --- a/openpype/hosts/photoshop/plugins/create/create_image.py +++ b/openpype/hosts/photoshop/plugins/create/create_image.py @@ -3,8 +3,7 @@ from openpype.hosts.photoshop import api from openpype.pipeline import ( Creator, CreatedInstance, - lib, - CreatorError + lib ) @@ -30,65 +29,53 @@ class ImageCreator(Creator): ) self._add_instance_to_context(instance) - def create(self, subset_name, data, pre_create_data): - groups = [] - layers = [] - create_group = False + def create(self, subset_name_from_ui, data, pre_create_data): + groups_to_create = [] + top_layers_to_wrap = [] + create_empty_group = False stub = api.stub() # only after PS is up - multiple_instances = pre_create_data.get("create_multiple") - selection = stub.get_selected_layers() + top_level_selected_items = stub.get_selected_layers() if pre_create_data.get("use_selection"): - if len(selection) > 1: - if multiple_instances: - for item in selection: - if item.group: - groups.append(item) - else: - layers.append(item) + only_single_item_selected = len(top_level_selected_items) == 1 + for selected_item in top_level_selected_items: + if only_single_item_selected or pre_create_data.get("create_multiple"): + if selected_item.group: + groups_to_create.append(selected_item) + else: + top_layers_to_wrap.append(selected_item) else: - group = stub.group_selected_layers(subset_name) - groups.append(group) - elif len(selection) == 1: - # One selected item. Use group if its a LayerSet (group), else - # create a new group. - selected_item = selection[0] - if selected_item.group: - groups.append(selected_item) - else: - layers.append(selected_item) - elif len(selection) == 0: - # No selection creates an empty group. - create_group = True - else: - group = stub.create_group(subset_name) - groups.append(group) + group = stub.group_selected_layers(subset_name_from_ui) + groups_to_create.append(group) - if create_group: - group = stub.create_group(subset_name) - groups.append(group) + if not groups_to_create and not top_layers_to_wrap: + group = stub.create_group(subset_name_from_ui) + groups_to_create.append(group) - for layer in layers: + # wrap each top level layer into separate new group + for layer in top_layers_to_wrap: stub.select_layers([layer]) group = stub.group_selected_layers(layer.name) - groups.append(group) + groups_to_create.append(group) - for group in groups: - long_names = [] - group.name = self._clean_highlights(stub, group.name) + creating_multiple_groups = len(groups_to_create) > 1 + for group in groups_to_create: + subset_name = subset_name_from_ui # reset to name from creator UI + layer_names_in_hierarchy = [] + created_group_name = self._clean_highlights(stub, group.name) - if len(groups) > 1: + if creating_multiple_groups: + # concatenate with layer name to differentiate subsets subset_name += group.name.title().replace(" ", "") if group.long_name: for directory in group.long_name[::-1]: name = self._clean_highlights(stub, directory) - long_names.append(name) + layer_names_in_hierarchy.append(name) data.update({"subset": subset_name}) - data.update({"layer": group}) data.update({"members": [str(group.id)]}) - data.update({"long_name": "_".join(long_names)}) + data.update({"long_name": "_".join(layer_names_in_hierarchy)}) new_instance = CreatedInstance(self.family, subset_name, data, self) @@ -97,8 +84,8 @@ class ImageCreator(Creator): new_instance.data_to_store()) self._add_instance_to_context(new_instance) # reusing existing group, need to rename afterwards - if not create_group: - stub.rename_layer(group.id, stub.PUBLISH_ICON + group.name) + if not create_empty_group: + stub.rename_layer(group.id, stub.PUBLISH_ICON + created_group_name) def update_instances(self, update_list): self.log.debug("update_list:: {}".format(update_list)) @@ -120,7 +107,7 @@ class ImageCreator(Creator): def get_pre_create_attr_defs(self): output = [ - lib.BoolDef("use_selection", default=True, label="Use selection"), + lib.BoolDef("use_selection", default=True, label="Create only for selected"), lib.BoolDef("create_multiple", default=True, label="Create separate instance for each selected") From 9be8885bc3845d3fd5a4aed6b9558a3758e38a8b Mon Sep 17 00:00:00 2001 From: Pype Club Date: Wed, 23 Mar 2022 10:47:50 +0100 Subject: [PATCH 17/32] OP-2766 - added support for new publisher NP already collected instances, need to only add layer information --- .../plugins/publish/collect_instances.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/publish/collect_instances.py b/openpype/hosts/photoshop/plugins/publish/collect_instances.py index d506b9a5bf..1b30fb053a 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_instances.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_instances.py @@ -1,3 +1,4 @@ +import pprint import pyblish.api from openpype.hosts.photoshop import api as photoshop @@ -21,9 +22,10 @@ class CollectInstances(pyblish.api.ContextPlugin): } def process(self, context): - if context.data.get("newPublishing"): - self.log.debug("Not applicable for New Publisher, skip") - return + instance_by_layer_id = {} + for instance in context: + if instance.data["family"] == "image" and instance.data.get("members"): + instance_by_layer_id[str(instance.data["members"][0])] = instance stub = photoshop.stub() layers = stub.get_layers() @@ -40,13 +42,10 @@ class CollectInstances(pyblish.api.ContextPlugin): if "container" in layer_data["id"]: continue - # child_layers = [*layer.Layers] - # self.log.debug("child_layers {}".format(child_layers)) - # if not child_layers: - # self.log.info("%s skipped, it was empty." % layer.Name) - # continue + instance = instance_by_layer_id.get(str(layer.id)) + if instance is None: + instance = context.create_instance(layer_data["subset"]) - instance = context.create_instance(layer_data["subset"]) instance.data["layer"] = layer instance.data.update(layer_data) instance.data["families"] = self.families_mapping[ @@ -58,7 +57,7 @@ class CollectInstances(pyblish.api.ContextPlugin): # Produce diagnostic message for any graphical # user interface interested in visualising it. self.log.info("Found: \"%s\" " % instance.data["name"]) - self.log.info("instance: {} ".format(instance.data)) + self.log.info("instance: {} ".format(pprint.pformat(instance.data, indent=4))) if len(instance_names) != len(set(instance_names)): self.log.warning("Duplicate instances found. " + From 11a9ad18738ffa9ff036722f699d715663d3fb53 Mon Sep 17 00:00:00 2001 From: Pype Club Date: Wed, 23 Mar 2022 10:53:58 +0100 Subject: [PATCH 18/32] OP-2766 - refactor --- .../plugins/publish/collect_instances.py | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/publish/collect_instances.py b/openpype/hosts/photoshop/plugins/publish/collect_instances.py index 1b30fb053a..9449662067 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_instances.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_instances.py @@ -7,8 +7,8 @@ from openpype.hosts.photoshop import api as photoshop class CollectInstances(pyblish.api.ContextPlugin): """Gather instances by LayerSet and file metadata - This collector takes into account assets that are associated with - an LayerSet and marked with a unique identifier; + Collects publishable instances from file metadata or enhance + already collected by creator (family == "image"). Identifier: id (str): "pyblish.avalon.instance" @@ -24,40 +24,44 @@ class CollectInstances(pyblish.api.ContextPlugin): def process(self, context): instance_by_layer_id = {} for instance in context: - if instance.data["family"] == "image" and instance.data.get("members"): - instance_by_layer_id[str(instance.data["members"][0])] = instance + if ( + instance.data["family"] == "image" and + instance.data.get("members")): + layer_id = str(instance.data["members"][0]) + instance_by_layer_id[layer_id] = instance stub = photoshop.stub() - layers = stub.get_layers() + layer_items = stub.get_layers() layers_meta = stub.get_layers_metadata() instance_names = [] - for layer in layers: - layer_data = stub.read(layer, layers_meta) + for layer_item in layer_items: + layer_instance_data = stub.read(layer_item, layers_meta) # Skip layers without metadata. - if layer_data is None: + if layer_instance_data is None: continue # Skip containers. - if "container" in layer_data["id"]: + if "container" in layer_instance_data["id"]: continue - instance = instance_by_layer_id.get(str(layer.id)) + instance = instance_by_layer_id.get(str(layer_item.id)) if instance is None: - instance = context.create_instance(layer_data["subset"]) + instance = context.create_instance(layer_instance_data["subset"]) - instance.data["layer"] = layer - instance.data.update(layer_data) + instance.data["layer"] = layer_item + instance.data.update(layer_instance_data) instance.data["families"] = self.families_mapping[ - layer_data["family"] + layer_instance_data["family"] ] - instance.data["publish"] = layer.visible - instance_names.append(layer_data["subset"]) + instance.data["publish"] = layer_item.visible + instance_names.append(layer_instance_data["subset"]) # Produce diagnostic message for any graphical # user interface interested in visualising it. self.log.info("Found: \"%s\" " % instance.data["name"]) - self.log.info("instance: {} ".format(pprint.pformat(instance.data, indent=4))) + self.log.info("instance: {} ".format( + pprint.pformat(instance.data, indent=4))) if len(instance_names) != len(set(instance_names)): self.log.warning("Duplicate instances found. " + From 755a6dabfd1ba5d1bb80000ab69140d1a54d9c3d Mon Sep 17 00:00:00 2001 From: Pype Club Date: Wed, 23 Mar 2022 11:47:36 +0100 Subject: [PATCH 19/32] OP-2766 - added NP validators for subset names and uniqueness --- .../plugins/publish/help/validate_naming.xml | 21 +++++++++ .../publish/help/validate_unique_subsets.xml | 14 ++++++ .../plugins/publish/validate_naming.py | 47 +++++++++++-------- .../publish/validate_unique_subsets.py | 9 +++- 4 files changed, 71 insertions(+), 20 deletions(-) create mode 100644 openpype/hosts/photoshop/plugins/publish/help/validate_naming.xml create mode 100644 openpype/hosts/photoshop/plugins/publish/help/validate_unique_subsets.xml diff --git a/openpype/hosts/photoshop/plugins/publish/help/validate_naming.xml b/openpype/hosts/photoshop/plugins/publish/help/validate_naming.xml new file mode 100644 index 0000000000..5a1e266748 --- /dev/null +++ b/openpype/hosts/photoshop/plugins/publish/help/validate_naming.xml @@ -0,0 +1,21 @@ + + + +Subset name + +## Invalid subset or layer name + +Subset or layer name cannot contain specific characters (spaces etc) which could cause issue when subset name is used in a published file name. + {msg} + +### How to repair? + +You can fix this with "repair" button on the right. + + +### __Detailed Info__ (optional) + +Not all characters are available in a file names on all OS. Wrong characters could be configured in Settings. + + + \ No newline at end of file diff --git a/openpype/hosts/photoshop/plugins/publish/help/validate_unique_subsets.xml b/openpype/hosts/photoshop/plugins/publish/help/validate_unique_subsets.xml new file mode 100644 index 0000000000..4b47973193 --- /dev/null +++ b/openpype/hosts/photoshop/plugins/publish/help/validate_unique_subsets.xml @@ -0,0 +1,14 @@ + + + +Subset not unique + +## Non unique subset name found + + Non unique subset names: '{non_unique}' +### How to repair? + +Remove offending instance, rename it to have unique name. Maybe layer name wasn't used for multiple instances? + + + \ No newline at end of file diff --git a/openpype/hosts/photoshop/plugins/publish/validate_naming.py b/openpype/hosts/photoshop/plugins/publish/validate_naming.py index b40e44d016..c0ca4cfb69 100644 --- a/openpype/hosts/photoshop/plugins/publish/validate_naming.py +++ b/openpype/hosts/photoshop/plugins/publish/validate_naming.py @@ -2,6 +2,7 @@ import re import pyblish.api import openpype.api +from openpype.pipeline import PublishXmlValidationError from openpype.hosts.photoshop import api as photoshop @@ -22,32 +23,33 @@ class ValidateNamingRepair(pyblish.api.Action): failed.append(result["instance"]) invalid_chars, replace_char = plugin.get_replace_chars() - self.log.info("{} --- {}".format(invalid_chars, replace_char)) + self.log.debug("{} --- {}".format(invalid_chars, replace_char)) # Apply pyblish.logic to get the instances for the plug-in instances = pyblish.api.instances_by_plugin(failed, plugin) stub = photoshop.stub() for instance in instances: - self.log.info("validate_naming instance {}".format(instance)) - metadata = stub.read(instance[0]) - self.log.info("metadata instance {}".format(metadata)) - layer_name = None - if metadata.get("uuid"): - layer_data = stub.get_layer(metadata["uuid"]) - self.log.info("layer_data {}".format(layer_data)) - if layer_data: - layer_name = re.sub(invalid_chars, - replace_char, - layer_data.name) + self.log.debug("validate_naming instance {}".format(instance)) + current_layer_state = stub.get_layer(instance.data["layer"].id) + self.log.debug("current_layer_state instance {}".format(current_layer_state)) - stub.rename_layer(instance.data["uuid"], layer_name) + layer_meta = stub.read(current_layer_state) + instance_id = layer_meta.get("instance_id") or layer_meta.get("uuid") + if not instance_id: + self.log.warning("Unable to repair, cannot find layer") + continue + + layer_name = re.sub(invalid_chars, + replace_char, + current_layer_state.name) + + stub.rename_layer(current_layer_state.id, layer_name) subset_name = re.sub(invalid_chars, replace_char, - instance.data["name"]) + instance.data["subset"]) - instance[0].Name = layer_name or subset_name - metadata["subset"] = subset_name - stub.imprint(instance[0], metadata) + layer_meta["subset"] = subset_name + stub.imprint(instance_id, layer_meta) return True @@ -72,11 +74,18 @@ class ValidateNaming(pyblish.api.InstancePlugin): help_msg = ' Use Repair action (A) in Pyblish to fix it.' msg = "Name \"{}\" is not allowed.{}".format(instance.data["name"], help_msg) - assert not re.search(self.invalid_chars, instance.data["name"]), msg + + formatting_data = {"msg": msg} + if re.search(self.invalid_chars, instance.data["name"]): + raise PublishXmlValidationError(self, msg, + formatting_data=formatting_data) msg = "Subset \"{}\" is not allowed.{}".format(instance.data["subset"], help_msg) - assert not re.search(self.invalid_chars, instance.data["subset"]), msg + formatting_data = {"msg": msg} + if re.search(self.invalid_chars, instance.data["subset"]): + raise PublishXmlValidationError(self, msg, + formatting_data=formatting_data) @classmethod def get_replace_chars(cls): diff --git a/openpype/hosts/photoshop/plugins/publish/validate_unique_subsets.py b/openpype/hosts/photoshop/plugins/publish/validate_unique_subsets.py index 40abfb1bbd..01f2323157 100644 --- a/openpype/hosts/photoshop/plugins/publish/validate_unique_subsets.py +++ b/openpype/hosts/photoshop/plugins/publish/validate_unique_subsets.py @@ -1,6 +1,7 @@ import collections import pyblish.api import openpype.api +from openpype.pipeline import PublishXmlValidationError class ValidateSubsetUniqueness(pyblish.api.ContextPlugin): @@ -27,4 +28,10 @@ class ValidateSubsetUniqueness(pyblish.api.ContextPlugin): if count > 1] msg = ("Instance subset names {} are not unique. ".format(non_unique) + "Remove duplicates via SubsetManager.") - assert not non_unique, msg + formatting_data = { + "non_unique": ",".join(non_unique) + } + + if non_unique: + raise PublishXmlValidationError(self, msg, + formatting_data=formatting_data) From 85b49da44e14ec82a93e43bd4f8f1571b403627a Mon Sep 17 00:00:00 2001 From: Pype Club Date: Wed, 23 Mar 2022 12:11:48 +0100 Subject: [PATCH 20/32] OP-2766 - skip non active instances --- .../plugins/publish/collect_instances.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/publish/collect_instances.py b/openpype/hosts/photoshop/plugins/publish/collect_instances.py index 9449662067..52a8310594 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_instances.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_instances.py @@ -35,27 +35,30 @@ class CollectInstances(pyblish.api.ContextPlugin): layers_meta = stub.get_layers_metadata() instance_names = [] for layer_item in layer_items: - layer_instance_data = stub.read(layer_item, layers_meta) + layer_meta_data = stub.read(layer_item, layers_meta) # Skip layers without metadata. - if layer_instance_data is None: + if layer_meta_data is None: continue # Skip containers. - if "container" in layer_instance_data["id"]: + if "container" in layer_meta_data["id"]: + continue + + if not layer_meta_data.get("active", True): # active might not be in legacy meta continue instance = instance_by_layer_id.get(str(layer_item.id)) if instance is None: - instance = context.create_instance(layer_instance_data["subset"]) + instance = context.create_instance(layer_meta_data["subset"]) instance.data["layer"] = layer_item - instance.data.update(layer_instance_data) + instance.data.update(layer_meta_data) instance.data["families"] = self.families_mapping[ - layer_instance_data["family"] + layer_meta_data["family"] ] instance.data["publish"] = layer_item.visible - instance_names.append(layer_instance_data["subset"]) + instance_names.append(layer_meta_data["subset"]) # Produce diagnostic message for any graphical # user interface interested in visualising it. From d211471ea099f53d8349f33d7e20ad29da7f178c Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 23 Mar 2022 13:49:50 +0100 Subject: [PATCH 21/32] OP-2766 - Hound --- openpype/hosts/photoshop/api/pipeline.py | 4 ++-- .../photoshop/plugins/create/create_image.py | 15 +++++++++------ .../plugins/publish/collect_instances.py | 3 ++- .../photoshop/plugins/publish/validate_naming.py | 5 +++-- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/openpype/hosts/photoshop/api/pipeline.py b/openpype/hosts/photoshop/api/pipeline.py index 1b471ef1d3..db40e456db 100644 --- a/openpype/hosts/photoshop/api/pipeline.py +++ b/openpype/hosts/photoshop/api/pipeline.py @@ -151,7 +151,7 @@ def list_instances(): layers_meta = stub.get_layers_metadata() if layers_meta: for instance in layers_meta: - if instance.get("id") == "pyblish.avalon.instance": # TODO only this way? + if instance.get("id") == "pyblish.avalon.instance": instances.append(instance) return instances @@ -266,4 +266,4 @@ def get_context_title(): project_name = avalon.api.Session["AVALON_PROJECT"] asset_name = avalon.api.Session["AVALON_ASSET"] task_name = avalon.api.Session["AVALON_TASK"] - return "{}/{}/{}".format(project_name, asset_name, task_name) \ No newline at end of file + return "{}/{}/{}".format(project_name, asset_name, task_name) diff --git a/openpype/hosts/photoshop/plugins/create/create_image.py b/openpype/hosts/photoshop/plugins/create/create_image.py index cd7e219bd0..e332cfd9c2 100644 --- a/openpype/hosts/photoshop/plugins/create/create_image.py +++ b/openpype/hosts/photoshop/plugins/create/create_image.py @@ -39,7 +39,9 @@ class ImageCreator(Creator): if pre_create_data.get("use_selection"): only_single_item_selected = len(top_level_selected_items) == 1 for selected_item in top_level_selected_items: - if only_single_item_selected or pre_create_data.get("create_multiple"): + if ( + only_single_item_selected or + pre_create_data.get("create_multiple")): if selected_item.group: groups_to_create.append(selected_item) else: @@ -85,13 +87,15 @@ class ImageCreator(Creator): self._add_instance_to_context(new_instance) # reusing existing group, need to rename afterwards if not create_empty_group: - stub.rename_layer(group.id, stub.PUBLISH_ICON + created_group_name) + stub.rename_layer(group.id, + stub.PUBLISH_ICON + created_group_name) def update_instances(self, update_list): self.log.debug("update_list:: {}".format(update_list)) for created_inst, _changes in update_list: if created_inst.get("layer"): - created_inst.pop("layer") # not storing PSItem layer to metadata + # not storing PSItem layer to metadata + created_inst.pop("layer") api.stub().imprint(created_inst.get("instance_id"), created_inst.data_to_store()) @@ -107,7 +111,8 @@ class ImageCreator(Creator): def get_pre_create_attr_defs(self): output = [ - lib.BoolDef("use_selection", default=True, label="Create only for selected"), + lib.BoolDef("use_selection", default=True, + label="Create only for selected"), lib.BoolDef("create_multiple", default=True, label="Create separate instance for each selected") @@ -138,5 +143,3 @@ class ImageCreator(Creator): def _clean_highlights(self, stub, item): return item.replace(stub.PUBLISH_ICON, '').replace(stub.LOADED_ICON, '') - - diff --git a/openpype/hosts/photoshop/plugins/publish/collect_instances.py b/openpype/hosts/photoshop/plugins/publish/collect_instances.py index 52a8310594..a7bb2d40c7 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_instances.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_instances.py @@ -45,7 +45,8 @@ class CollectInstances(pyblish.api.ContextPlugin): if "container" in layer_meta_data["id"]: continue - if not layer_meta_data.get("active", True): # active might not be in legacy meta + # active might not be in legacy meta + if not layer_meta_data.get("active", True): continue instance = instance_by_layer_id.get(str(layer_item.id)) diff --git a/openpype/hosts/photoshop/plugins/publish/validate_naming.py b/openpype/hosts/photoshop/plugins/publish/validate_naming.py index c0ca4cfb69..bcae24108c 100644 --- a/openpype/hosts/photoshop/plugins/publish/validate_naming.py +++ b/openpype/hosts/photoshop/plugins/publish/validate_naming.py @@ -31,10 +31,11 @@ class ValidateNamingRepair(pyblish.api.Action): for instance in instances: self.log.debug("validate_naming instance {}".format(instance)) current_layer_state = stub.get_layer(instance.data["layer"].id) - self.log.debug("current_layer_state instance {}".format(current_layer_state)) + self.log.debug("current_layer{}".format(current_layer_state)) layer_meta = stub.read(current_layer_state) - instance_id = layer_meta.get("instance_id") or layer_meta.get("uuid") + instance_id = (layer_meta.get("instance_id") or + layer_meta.get("uuid")) if not instance_id: self.log.warning("Unable to repair, cannot find layer") continue From 49d26ef9593271a6b36dfbdd353f7bed017478ad Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 23 Mar 2022 14:11:39 +0100 Subject: [PATCH 22/32] OP-2766 - changed imports after refactor of attribute definitions --- openpype/hosts/photoshop/plugins/create/create_image.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/create/create_image.py b/openpype/hosts/photoshop/plugins/create/create_image.py index e332cfd9c2..12898bb7f4 100644 --- a/openpype/hosts/photoshop/plugins/create/create_image.py +++ b/openpype/hosts/photoshop/plugins/create/create_image.py @@ -1,9 +1,9 @@ from avalon import api as avalon_api from openpype.hosts.photoshop import api +from openpype.lib import BoolDef from openpype.pipeline import ( Creator, - CreatedInstance, - lib + CreatedInstance ) @@ -111,9 +111,9 @@ class ImageCreator(Creator): def get_pre_create_attr_defs(self): output = [ - lib.BoolDef("use_selection", default=True, + BoolDef("use_selection", default=True, label="Create only for selected"), - lib.BoolDef("create_multiple", + BoolDef("create_multiple", default=True, label="Create separate instance for each selected") ] From 1534c878d2e57dad50823d52d434feb2cecd3f10 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 23 Mar 2022 14:33:49 +0100 Subject: [PATCH 23/32] OP-2766 - Hound --- openpype/hosts/photoshop/plugins/create/create_image.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/create/create_image.py b/openpype/hosts/photoshop/plugins/create/create_image.py index 12898bb7f4..c2fe8b6c78 100644 --- a/openpype/hosts/photoshop/plugins/create/create_image.py +++ b/openpype/hosts/photoshop/plugins/create/create_image.py @@ -112,10 +112,10 @@ class ImageCreator(Creator): def get_pre_create_attr_defs(self): output = [ BoolDef("use_selection", default=True, - label="Create only for selected"), + label="Create only for selected"), BoolDef("create_multiple", - default=True, - label="Create separate instance for each selected") + default=True, + label="Create separate instance for each selected") ] return output From c7039e91f8665b1a3f47e317e5b807faee03783c Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 23 Mar 2022 15:20:43 +0100 Subject: [PATCH 24/32] OP-2766 - return back uuid for legacy creator --- openpype/hosts/photoshop/plugins/create/create_legacy_image.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hosts/photoshop/plugins/create/create_legacy_image.py b/openpype/hosts/photoshop/plugins/create/create_legacy_image.py index 6fa455fa03..9736471a26 100644 --- a/openpype/hosts/photoshop/plugins/create/create_legacy_image.py +++ b/openpype/hosts/photoshop/plugins/create/create_legacy_image.py @@ -91,6 +91,7 @@ class CreateImage(create.LegacyCreator): long_names.append(name) self.data.update({"subset": subset_name}) + self.data.update({"uuid": str(group.id)}) self.data.update({"members": [str(group.id)]}) self.data.update({"long_name": "_".join(long_names)}) stub.imprint(group, self.data) From af092348e50e1bda0ac6b3a13a58f1908cf5b939 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 29 Mar 2022 16:32:32 +0200 Subject: [PATCH 25/32] OP-2766 - Fix creation of subset names in PS review and workfile --- .../hosts/photoshop/plugins/publish/collect_review.py | 10 +++++++++- .../photoshop/plugins/publish/collect_workfile.py | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/publish/collect_review.py b/openpype/hosts/photoshop/plugins/publish/collect_review.py index 4b6f855a6a..dafeb95d0e 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_review.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_review.py @@ -10,6 +10,8 @@ import os import pyblish.api +from openpype.lib import get_subset_name + class CollectReview(pyblish.api.ContextPlugin): """Gather the active document as review instance. @@ -25,7 +27,13 @@ class CollectReview(pyblish.api.ContextPlugin): def process(self, context): family = "review" task = os.getenv("AVALON_TASK", None) - subset = family + task.capitalize() + subset = get_subset_name( + family, + "", + task, + context.data["assetEntity"]["_id"], + host_name="photoshop" + ) instance = context.create_instance(subset) instance.data.update({ diff --git a/openpype/hosts/photoshop/plugins/publish/collect_workfile.py b/openpype/hosts/photoshop/plugins/publish/collect_workfile.py index bdbd379a33..1a826c3f2a 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_workfile.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_workfile.py @@ -1,6 +1,8 @@ import os import pyblish.api +from openpype.lib import get_subset_name + class CollectWorkfile(pyblish.api.ContextPlugin): """Collect current script for publish.""" @@ -19,7 +21,13 @@ class CollectWorkfile(pyblish.api.ContextPlugin): family = "workfile" task = os.getenv("AVALON_TASK", None) - subset = family + task.capitalize() + subset = get_subset_name( + family, + "", + task, + context.data["assetEntity"]["_id"], + host_name="photoshop" + ) file_path = context.data["currentFile"] staging_dir = os.path.dirname(file_path) From 0f08f3e31df5a6ec54c025776d490343a587ab5b Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 29 Mar 2022 17:25:19 +0200 Subject: [PATCH 26/32] OP-2766 - Fix pulling task and project from context --- openpype/hosts/photoshop/plugins/publish/collect_review.py | 5 +++-- openpype/hosts/photoshop/plugins/publish/collect_workfile.py | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/publish/collect_review.py b/openpype/hosts/photoshop/plugins/publish/collect_review.py index dafeb95d0e..09fed2df78 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_review.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_review.py @@ -23,15 +23,16 @@ class CollectReview(pyblish.api.ContextPlugin): label = "Collect Review" order = pyblish.api.CollectorOrder hosts = ["photoshop"] + order = pyblish.api.CollectorOrder + 0.1 def process(self, context): family = "review" - task = os.getenv("AVALON_TASK", None) subset = get_subset_name( family, "", - task, + context.data["anatomyData"]["task"]["name"], context.data["assetEntity"]["_id"], + context.data["anatomyData"]["project"]["name"], host_name="photoshop" ) diff --git a/openpype/hosts/photoshop/plugins/publish/collect_workfile.py b/openpype/hosts/photoshop/plugins/publish/collect_workfile.py index 1a826c3f2a..71022a86fd 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_workfile.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_workfile.py @@ -20,12 +20,12 @@ class CollectWorkfile(pyblish.api.ContextPlugin): break family = "workfile" - task = os.getenv("AVALON_TASK", None) subset = get_subset_name( family, "", - task, + context.data["anatomyData"]["task"]["name"], context.data["assetEntity"]["_id"], + context.data["anatomyData"]["project"]["name"], host_name="photoshop" ) From 9e4e6d4b85a1273d1eeab0f473c88cb8b7f62f30 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 30 Mar 2022 13:30:53 +0200 Subject: [PATCH 27/32] OP-2766 Switched subset function according to review comments --- .../hosts/photoshop/plugins/publish/collect_review.py | 8 ++++---- .../hosts/photoshop/plugins/publish/collect_workfile.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/publish/collect_review.py b/openpype/hosts/photoshop/plugins/publish/collect_review.py index 09fed2df78..d825950b9e 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_review.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_review.py @@ -10,7 +10,7 @@ import os import pyblish.api -from openpype.lib import get_subset_name +from openpype.lib import get_subset_name_with_asset_doc class CollectReview(pyblish.api.ContextPlugin): @@ -27,13 +27,13 @@ class CollectReview(pyblish.api.ContextPlugin): def process(self, context): family = "review" - subset = get_subset_name( + subset = get_subset_name_with_asset_doc( family, "", context.data["anatomyData"]["task"]["name"], - context.data["assetEntity"]["_id"], + context.data["assetEntity"], context.data["anatomyData"]["project"]["name"], - host_name="photoshop" + host_name=context.data["hostName"] ) instance = context.create_instance(subset) diff --git a/openpype/hosts/photoshop/plugins/publish/collect_workfile.py b/openpype/hosts/photoshop/plugins/publish/collect_workfile.py index 71022a86fd..e4f0a07b34 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_workfile.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_workfile.py @@ -1,7 +1,7 @@ import os import pyblish.api -from openpype.lib import get_subset_name +from openpype.lib import get_subset_name_with_asset_doc class CollectWorkfile(pyblish.api.ContextPlugin): @@ -20,13 +20,13 @@ class CollectWorkfile(pyblish.api.ContextPlugin): break family = "workfile" - subset = get_subset_name( + subset = get_subset_name_with_asset_doc( family, "", context.data["anatomyData"]["task"]["name"], - context.data["assetEntity"]["_id"], + context.data["assetEntity"], context.data["anatomyData"]["project"]["name"], - host_name="photoshop" + host_name=context.data["hostName"] ) file_path = context.data["currentFile"] From 80ee8c523ad20df67ddfd763933b47fc4e6a3b0d Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 1 Apr 2022 18:07:47 +0200 Subject: [PATCH 28/32] OP-2766 - clean up logging --- openpype/hosts/photoshop/plugins/create/workfile_creator.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/create/workfile_creator.py b/openpype/hosts/photoshop/plugins/create/workfile_creator.py index 2a2fda3cc4..d66a05cad7 100644 --- a/openpype/hosts/photoshop/plugins/create/workfile_creator.py +++ b/openpype/hosts/photoshop/plugins/create/workfile_creator.py @@ -15,7 +15,6 @@ class PSWorkfileCreator(AutoCreator): return [] def collect_instances(self): - print("coll::{}".format(api.list_instances())) for instance_data in api.list_instances(): creator_id = instance_data.get("creator_identifier") if creator_id == self.identifier: @@ -30,7 +29,6 @@ class PSWorkfileCreator(AutoCreator): pass def create(self, options=None): - print("create") existing_instance = None for instance in self.create_context.instances: if instance.family == self.family: From 9efa30d7569f0025cdd8a2d1f9a970edfdbb1aad Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 1 Apr 2022 18:09:38 +0200 Subject: [PATCH 29/32] OP-2766 - revert unwanted commit --- .../aftereffects/plugins/publish/collect_workfile.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/openpype/hosts/aftereffects/plugins/publish/collect_workfile.py b/openpype/hosts/aftereffects/plugins/publish/collect_workfile.py index 1983851028..c1c2be4855 100644 --- a/openpype/hosts/aftereffects/plugins/publish/collect_workfile.py +++ b/openpype/hosts/aftereffects/plugins/publish/collect_workfile.py @@ -38,13 +38,7 @@ class CollectWorkfile(pyblish.api.ContextPlugin): # workfile instance family = "workfile" - subset = get_subset_name( - family, - "", - task, - context.data["assetEntity"]["_id"], - host_name="photoshop" - ) + subset = family + task.capitalize() # Create instance instance = context.create_instance(subset) From d92ccf8c2ee97e38d236cd20764f9a3432a3e1a3 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 1 Apr 2022 18:11:26 +0200 Subject: [PATCH 30/32] OP-2766 - cleanup logging --- openpype/hosts/photoshop/plugins/publish/extract_image.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/publish/extract_image.py b/openpype/hosts/photoshop/plugins/publish/extract_image.py index 75e6323da7..a133e33409 100644 --- a/openpype/hosts/photoshop/plugins/publish/extract_image.py +++ b/openpype/hosts/photoshop/plugins/publish/extract_image.py @@ -16,8 +16,6 @@ class ExtractImage(openpype.api.Extractor): formats = ["png", "jpg"] def process(self, instance): - print("PPPPPP") - self.log.info("fdfdsfdfs") staging_dir = self.staging_dir(instance) self.log.info("Outputting image to {}".format(staging_dir)) From b16b1ee5c48df8438cbe716561df437f941e24c1 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 5 Apr 2022 16:39:51 +0200 Subject: [PATCH 31/32] OP-2766 - fix broken merge --- openpype/hosts/photoshop/api/pipeline.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openpype/hosts/photoshop/api/pipeline.py b/openpype/hosts/photoshop/api/pipeline.py index 54db09be2d..2e2717d420 100644 --- a/openpype/hosts/photoshop/api/pipeline.py +++ b/openpype/hosts/photoshop/api/pipeline.py @@ -78,8 +78,7 @@ def install(): pyblish.api.register_plugin_path(PUBLISH_PATH) register_loader_plugin_path(LOAD_PATH) - avalon.api.register_plugin_path(LegacyCreator, CREATE_PATH) - avalon.api.register_plugin_path(BaseCreator, CREATE_PATH) + register_creator_plugin_path(CREATE_PATH) log.info(PUBLISH_PATH) pyblish.api.register_callback( From 43a6863dc534ab514a91a9ade561c9c82e87f277 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 5 Apr 2022 16:40:16 +0200 Subject: [PATCH 32/32] OP-2766 - added documentation and resources for New Publisher --- website/docs/artist_hosts_photoshop.md | 64 ++++++++++++++++++ ...rtist_photoshop_new_publisher_instance.png | Bin 0 -> 21366 bytes ...otoshop_new_publisher_instance_created.png | Bin 0 -> 27811 bytes ...photoshop_new_publisher_publish_failed.png | Bin 0 -> 27081 bytes ...rtist_photoshop_new_publisher_workfile.png | Bin 0 -> 22231 bytes .../docs/assets/experimental_tools_menu.png | Bin 0 -> 9307 bytes .../assets/experimental_tools_settings.png | Bin 0 -> 8543 bytes 7 files changed, 64 insertions(+) create mode 100644 website/docs/assets/artist_photoshop_new_publisher_instance.png create mode 100644 website/docs/assets/artist_photoshop_new_publisher_instance_created.png create mode 100644 website/docs/assets/artist_photoshop_new_publisher_publish_failed.png create mode 100644 website/docs/assets/artist_photoshop_new_publisher_workfile.png create mode 100644 website/docs/assets/experimental_tools_menu.png create mode 100644 website/docs/assets/experimental_tools_settings.png diff --git a/website/docs/artist_hosts_photoshop.md b/website/docs/artist_hosts_photoshop.md index a140170c49..36670054ee 100644 --- a/website/docs/artist_hosts_photoshop.md +++ b/website/docs/artist_hosts_photoshop.md @@ -111,3 +111,67 @@ You can switch to a previous version of the image or update to the latest. ![Loader](assets/photoshop_manage_switch.gif) ![Loader](assets/photoshop_manage_update.gif) + + +### New Publisher + +All previous screenshot came from regular [pyblish](https://pyblish.com/) process, there is also a different UI available. This process extends existing implementation and adds new functionalities. + +To test this in Photoshop, the artist needs first to enable experimental `New publisher` in Settings. (Tray > Settings > Experimental tools) +![Settings](assets/experimental_tools_settings.png) + +New dialog opens after clicking on `Experimental tools` button in Openpype extension menu. +![Menu](assets/experimental_tools_menu.png) + +After you click on this button, this dialog will show up. + +![Menu](assets/artist_photoshop_new_publisher_workfile.png) + +You can see the first instance, called `workfileYourTaskName`. (Name depends on studio naming convention for Photoshop's workfiles.). This instance is so called "automatic", +it was created without instigation by the artist. You shouldn't delete this instance as it might hold necessary values for future publishing, but you can choose to skip it +from publishing (by toggling the pill button inside of the rectangular object denoting instance). + +New publisher allows publishing into different context, just click on a workfile instance, update `Variant`, `Asset` or `Task` in the form in the middle and don't forget to click on the 'Confirm' button. + +Similarly to the old publishing approach, you need to create instances for everything you want to publish. You will initiate by clicking on the '+' sign in the bottom left corner. + +![Instance creator](assets/artist_photoshop_new_publisher_instance.png) + +In this dialog you can select the family for the published layer or group. Currently only 'image' is implemented. + +On right hand side you can see creator attributes: +- `Create only for selected` - mimics `Use selected` option of regular publish +- `Create separate instance for each selected` - if separate instance should be created for each layer if multiple selected + +![Instance created](assets/artist_photoshop_new_publisher_instance_created.png) + +Here you can see a newly created instance of image family. (Name depends on studio naming convention for image family.) You can disable instance from publishing in the same fashion as a workfile instance. +You could also decide delete instance by selecting it and clicking on a trashcan icon (next to plus button on left button) + +Buttons on the bottom right are for: +- `Refresh publishing` - set publishing process to starting position - useful if previous publish failed, or you changed configuration of a publish +- `Stop/pause publishing` - if you would like to pause publishing process at any time +- `Validate` - if you would like to run only collecting and validating phases (nothing will be published yet) +- `Publish` - standard way how to kick off full publishing process + +In the unfortunate case of some error during publishing, you would receive this kind of error dialog. + +![Publish failed](assets/artist_photoshop_new_publisher_publish_failed.png) + +In this case there is an issue that you are publishing two or more instances with the same subset name ('imageMaing'). If the error is recoverable by the artist, you should +see helpful information in a `How to repair?` section or fix it automatically by clicking on a 'Wrench' button on the right if present. + +If you would like to ask for help admin or support, you could use any of the three buttons on bottom left: +- `Copy report` - stash full publishing log to a clipboard +- `Export and save report` - save log into a file for sending it via mail or any communication tool +- `Show details` - switches into a more detailed list of published instances and plugins. Similar to the old pyblish list. + +If you are able to fix the workfile yourself, use the first button on the right to set the UI to initial state before publish. (Click the `Publish` button to start again.) + +New publishing process should be backward compatible, eg. if you have a workfile with instances created in the previous publishing approach, they will be translated automatically and +could be used right away. + +If you would create instances in a new publisher, you cannot use them in the old approach though! + +If you would hit on unexpected behaviour with old instances, contact support first, then you could try some steps to recover your publish. Delete instances in New publisher UI, or try `Subset manager` in the extension menu. +Nuclear option is to purge workfile metadata in `File > File Info > Origin > Headline`. This is only for most determined daredevils though! diff --git a/website/docs/assets/artist_photoshop_new_publisher_instance.png b/website/docs/assets/artist_photoshop_new_publisher_instance.png new file mode 100644 index 0000000000000000000000000000000000000000..723a032c94488abf6ee60e11ab86b178e1cd5ade GIT binary patch literal 21366 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 literal 0 HcmV?d00001 diff --git a/website/docs/assets/artist_photoshop_new_publisher_publish_failed.png b/website/docs/assets/artist_photoshop_new_publisher_publish_failed.png new file mode 100644 index 0000000000000000000000000000000000000000..e34497b77da37b31ebbf26882242ed73040eba64 GIT binary patch literal 27081 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
    `u+FfieK(csR09(%#9Hb075(8VbCH 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 SEsPCz0W~FU#hMq^Z~p^3&eD4T literal 0 HcmV?d00001 diff --git a/website/docs/assets/experimental_tools_settings.png b/website/docs/assets/experimental_tools_settings.png new file mode 100644 index 0000000000000000000000000000000000000000..4d514e8a8fc63292579bd7f4a8b63b20c7c8e3d9 GIT binary patch literal 8543 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 JD`nq>{U56@0@(ln literal 0 HcmV?d00001