From 785925f1cc2deae1387ea91b903779a832df08f0 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 6 Nov 2024 16:59:38 +0100 Subject: [PATCH 1/6] Vertical alignment distribution of data fix - Adjusted vertical alignment and distribution of data in the code to ensure proper handling and organization of clip metadata. --- client/ayon_hiero/api/plugin.py | 134 ++++++++++++++++++++------------ 1 file changed, 85 insertions(+), 49 deletions(-) diff --git a/client/ayon_hiero/api/plugin.py b/client/ayon_hiero/api/plugin.py index 6ecef54..96d390a 100644 --- a/client/ayon_hiero/api/plugin.py +++ b/client/ayon_hiero/api/plugin.py @@ -1,7 +1,7 @@ import os -from pprint import pformat import re import uuid +from copy import deepcopy import hiero @@ -418,8 +418,6 @@ def __init__(self, cls, context, path, **options): # inject folder data to representation dict folder_entity = self.context["folder"] self.data["folderAttributes"] = folder_entity["attrib"] - log.info("__init__ self.data: `{}`".format(pformat(self.data))) - log.info("__init__ options: `{}`".format(pformat(options))) # add active components to class if self.new_sequence: @@ -657,6 +655,10 @@ class PublishClip: Returns: hiero.core.TrackItem: hiero track item object with AYON tag """ + vertical_clip_match = {} + vertical_clip_used = {} + tag_data = {} + types = { "shot": "shot", "folder": "folder", @@ -672,7 +674,7 @@ class PublishClip: rename_default = False hierarchy_default = "{_folder_}/{_sequence_}/{_track_}" clip_name_default = "shot_{_trackIndex_:0>3}_{_clipIndex_:0>4}" - product_name_default = "" + base_product_name_default = "" review_track_default = "< none >" product_type_default = "plate" count_from_default = 10 @@ -700,8 +702,6 @@ def __init__( rename_index=0): self.rename_index = rename_index - self.vertical_clip_match = dict() - self.tag_data = dict() # adding ui inputs if any self.pre_create_data = pre_create_data or {} @@ -724,9 +724,6 @@ def __init__( if data: self.tag_data.update(data) - # add publish attribute to tag data - self.tag_data.update({"publish": True}) - # populate default data before we get other attributes self._populate_track_item_default_data() @@ -795,22 +792,24 @@ def _populate_attributes(self): log.debug( "____ self.shot_num: {}".format(self.shot_num)) - # publisher ui attribute inputs or default values if gui was not used + # publisher ui attribute inputs or default values if gui was not used def get(key): """Shorthand access for code readability""" return self.pre_create_data.get(key) # ui_inputs data or default values if gui was not used - self.rename = self.pre_create_data.get("clipRename", self.rename_default) + self.rename = self.pre_create_data.get( + "clipRename", self.rename_default) self.clip_name = get("clipName") or self.clip_name_default self.hierarchy = get("hierarchy") or self.hierarchy_default self.count_from = get("countFrom") or self.count_from_default self.count_steps = get("countSteps") or self.count_steps_default - self.product_name = get("productName") or self.product_name_default + self.base_product_name = ( + get("productName") or self.base_product_name_default) self.product_type = get("productType") or self.product_type_default self.vertical_sync = get("vSyncOn") or self.vertical_sync_default self.driving_layer = get("vSyncTrack") or self.driving_layer_default - self.review_track = get("reviewTrack") or self.review_track_default + self.review_track = get("reviewableTrack") or self.review_track_default self.audio = get("audio") or False self.hierarchy_data = { @@ -819,13 +818,12 @@ def get(key): } # build product name from layer name - if self.product_name == "": - self.product_name = self.track_name + if self.base_product_name == "": + self.base_product_name = self.track_name # create product for publishing self.product_name = ( - self.product_type + self.product_name.capitalize() - ) + f"{self.product_type}{self.base_product_name.capitalize()}") def _replace_hash_to_expression(self, name, text): """ Replace hash with number in correct padding. """ @@ -842,17 +840,22 @@ def _convert_to_tag_data(self): # define vertical sync attributes hero_track = True self.review_layer = "" - if self.vertical_sync: + if ( + self.vertical_sync + and self.track_name != self.driving_layer + ): # check if track name is not in driving layer - if self.track_name not in self.driving_layer: - # if it is not then define vertical sync as None - hero_track = False + # if it is not then define vertical sync as None + hero_track = False # increasing steps by index of rename iteration self.count_steps *= self.rename_index - hierarchy_formatting_data = dict() + hierarchy_formatting_data = {} + hierarchy_data = deepcopy(self.hierarchy_data) _data = self.track_item_default_data.copy() + + # QUESTION: what is this for? it seems we always have pre_create_data if self.pre_create_data: # adding tag metadata from ui @@ -877,48 +880,81 @@ def _convert_to_tag_data(self): _data.update({"shot": self.shot_num}) # solve # in test to pythonic expression - for _key, _value in self.hierarchy_data.items(): + for _key, _value in hierarchy_data.items(): if "#" not in _value: continue - self.hierarchy_data[_key] = self._replace_hash_to_expression( - _key, _value - ) + hierarchy_data[_key] = self._replace_hash_to_expression( + _key, _value) # fill up pythonic expresisons in hierarchy data - for _key, _value in self.hierarchy_data.items(): - hierarchy_formatting_data[_key] = _value.format(**_data) + for _key, _value in hierarchy_data.items(): + formatted_value = _value.format(**_data) + hierarchy_formatting_data[_key] = formatted_value + self.tag_data[_key] = formatted_value else: # if no gui mode then just pass default data - hierarchy_formatting_data = self.hierarchy_data + hierarchy_formatting_data = hierarchy_data - tag_hierarchy_data = self._solve_tag_hierarchy_data( + tag_instance_data = self._solve_tag_instance_data( hierarchy_formatting_data ) - tag_hierarchy_data.update({"heroTrack": True}) + tag_instance_data.update({"heroTrack": True}) if hero_track and self.vertical_sync: - self.vertical_clip_match.update({ - (self.clip_in, self.clip_out): tag_hierarchy_data - }) + self.vertical_clip_match.update( + {(self.clip_in, self.clip_out): tag_instance_data} + ) if not hero_track and self.vertical_sync: # driving layer is set as negative match - for (_in, _out), hero_data in self.vertical_clip_match.items(): - hero_data.update({"heroTrack": False}) - if _in == self.clip_in and _out == self.clip_out: - data_product_name = hero_data["productName"] - # add track index in case duplicity of names in hero data - if self.product_name in data_product_name: - hero_data["productName"] = self.product_name + str( - self.track_index) - # in case track name and product name is the same then add - if self.product_name == self.track_name: - hero_data["productName"] = self.product_name - # assign data to return hierarchy data to tag - tag_hierarchy_data = hero_data + for (hero_in, hero_out), hero_data in self.vertical_clip_match.items(): # noqa + """Iterate over all clips in vertical sync match + + If clip frame range is outside of hero clip frame range + then skip this clip and do not add to hierarchical shared + metadata to them. + """ + if self.clip_in < hero_in and self.clip_out > hero_out: + continue + + _distrib_data = deepcopy(hero_data) + _distrib_data["heroTrack"] = False + data_product_name = hero_data["productName"] + + # get used names list for duplicity check + used_names_list = self.vertical_clip_used.setdefault( + data_product_name, [] + ) + + clip_product_name = self.product_name + + # in case track name and product name is the same then add + if self.base_product_name == self.track_name: + clip_product_name = self.product_name + + # add track index in case duplicity of names in hero data + # INFO: this is for case where hero clip product name + # is the same as current clip product name + if clip_product_name in data_product_name: + clip_product_name = ( + f"{clip_product_name}{self.track_index}") + + # in case track clip product name had been already used + # then add product name with clip index + if clip_product_name in used_names_list: + clip_product_name = ( + f"{clip_product_name}{self.rename_index}") + + _distrib_data["productName"] = clip_product_name + # assign data to return hierarchy data to tag + tag_instance_data = _distrib_data + + # add used product name to used list to avoid duplicity + used_names_list.append(clip_product_name) + break # add data to return data dict - self.tag_data.update(tag_hierarchy_data) + self.tag_data.update(tag_instance_data) # add uuid to tag data self.tag_data["uuid"] = str(uuid.uuid4()) @@ -929,7 +965,7 @@ def _convert_to_tag_data(self): else: self.tag_data.update({"reviewTrack": None}) - def _solve_tag_hierarchy_data(self, hierarchy_formatting_data): + def _solve_tag_instance_data(self, hierarchy_formatting_data): """ Solve tag data from hierarchy data and templates. """ # fill up clip name and hierarchy keys hierarchy_filled = self.hierarchy.format(**hierarchy_formatting_data) From a2a30b5f313baead24188dd027879c30764ddd0d Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 7 Nov 2024 16:34:39 +0100 Subject: [PATCH 2/6] Adjust clip duplication check logic and form unique key for used clips. - Refactored condition to handle clip boundaries. - Added formation of a unique key for each used clip. --- client/ayon_hiero/api/plugin.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/client/ayon_hiero/api/plugin.py b/client/ayon_hiero/api/plugin.py index 96d390a..73ebe7e 100644 --- a/client/ayon_hiero/api/plugin.py +++ b/client/ayon_hiero/api/plugin.py @@ -914,17 +914,19 @@ def _convert_to_tag_data(self): then skip this clip and do not add to hierarchical shared metadata to them. """ - if self.clip_in < hero_in and self.clip_out > hero_out: + if self.clip_in < hero_in or self.clip_out > hero_out: continue _distrib_data = deepcopy(hero_data) _distrib_data["heroTrack"] = False + + # form used clip unique key data_product_name = hero_data["productName"] + new_clip_name = hero_data["newClipName"] # get used names list for duplicity check used_names_list = self.vertical_clip_used.setdefault( - data_product_name, [] - ) + f"{new_clip_name}{data_product_name}", []) clip_product_name = self.product_name From 0ab6151206dd0239f20ee5de3c790d516b452179 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 8 Nov 2024 14:45:27 +0100 Subject: [PATCH 3/6] improving distribution of hero track data and variant --- client/ayon_hiero/api/plugin.py | 29 +++-- .../plugins/create/create_shot_clip.py | 115 ++++++++++-------- 2 files changed, 84 insertions(+), 60 deletions(-) diff --git a/client/ayon_hiero/api/plugin.py b/client/ayon_hiero/api/plugin.py index 73ebe7e..92c33ce 100644 --- a/client/ayon_hiero/api/plugin.py +++ b/client/ayon_hiero/api/plugin.py @@ -674,7 +674,7 @@ class PublishClip: rename_default = False hierarchy_default = "{_folder_}/{_sequence_}/{_track_}" clip_name_default = "shot_{_trackIndex_:0>3}_{_clipIndex_:0>4}" - base_product_name_default = "" + base_product_variant_default = "" review_track_default = "< none >" product_type_default = "plate" count_from_default = 10 @@ -694,6 +694,11 @@ class PublishClip: "workfileFrameStart", "handleStart", "handleEnd" } + @classmethod + def restore_all_caches(cls): + cls.vertical_clip_match = {} + cls.vertical_clip_used = {} + def __init__( self, track_item, @@ -804,8 +809,8 @@ def get(key): self.hierarchy = get("hierarchy") or self.hierarchy_default self.count_from = get("countFrom") or self.count_from_default self.count_steps = get("countSteps") or self.count_steps_default - self.base_product_name = ( - get("productName") or self.base_product_name_default) + self.base_product_variant = ( + get("clipVariant") or self.base_product_variant_default) self.product_type = get("productType") or self.product_type_default self.vertical_sync = get("vSyncOn") or self.vertical_sync_default self.driving_layer = get("vSyncTrack") or self.driving_layer_default @@ -818,12 +823,15 @@ def get(key): } # build product name from layer name - if self.base_product_name == "": - self.base_product_name = self.track_name + if self.base_product_variant == "": + self.base_product_variant = self.track_name + self.variant = self.track_name + else: + self.variant = self.base_product_variant # create product for publishing self.product_name = ( - f"{self.product_type}{self.base_product_name.capitalize()}") + f"{self.product_type}{self.base_product_variant.capitalize()}") def _replace_hash_to_expression(self, name, text): """ Replace hash with number in correct padding. """ @@ -855,7 +863,8 @@ def _convert_to_tag_data(self): hierarchy_data = deepcopy(self.hierarchy_data) _data = self.track_item_default_data.copy() - # QUESTION: what is this for? it seems we always have pre_create_data + # in case we are running creators headless default + # precreate data values are used if self.pre_create_data: # adding tag metadata from ui @@ -931,7 +940,7 @@ def _convert_to_tag_data(self): clip_product_name = self.product_name # in case track name and product name is the same then add - if self.base_product_name == self.track_name: + if self.base_product_variant == self.track_name: clip_product_name = self.product_name # add track index in case duplicity of names in hero data @@ -948,6 +957,7 @@ def _convert_to_tag_data(self): f"{clip_product_name}{self.rename_index}") _distrib_data["productName"] = clip_product_name + _distrib_data["variant"] = self.variant # assign data to return hierarchy data to tag tag_instance_data = _distrib_data @@ -982,7 +992,8 @@ def _solve_tag_instance_data(self, hierarchy_formatting_data): "parents": self.parents, "hierarchyData": hierarchy_formatting_data, "productName": self.product_name, - "productType": self.product_type + "productType": self.product_type, + "variant": self.variant, } def _convert_to_entity(self, src_type, template): diff --git a/client/ayon_hiero/plugins/create/create_shot_clip.py b/client/ayon_hiero/plugins/create/create_shot_clip.py index 38d772e..3924ef1 100644 --- a/client/ayon_hiero/plugins/create/create_shot_clip.py +++ b/client/ayon_hiero/plugins/create/create_shot_clip.py @@ -100,8 +100,6 @@ def create(self, instance_data, _): CreatedInstance: The created instance object for the new shot. """ instance_data.update({ - "productName": f"{self.product_type}{instance_data['variant']}", - "productType": self.product_type, "newHierarchyIntegration": True, # Backwards compatible (Deprecated since 24/06/06) "newAssetPublishing": True, @@ -227,12 +225,6 @@ def create(self, instance_data, _): Return: CreatedInstance: The created instance object for the new shot. """ - if instance_data.get("clip_variant") == "": - instance_data["variant"] = instance_data["hierarchyData"]["track"] - - else: - instance_data["variant"] = instance_data["clip_variant"] - return super().create(instance_data, None) @@ -259,6 +251,8 @@ class CreateShotClip(plugin.HieroCreator): """ create_allow_thumbnail = False + shot_instances = {} + def get_pre_create_attr_defs(self): def header_label(text): @@ -387,7 +381,7 @@ def header_label(text): label=header_label("Publish Settings") ), EnumDef( - "clip_variant", + "clipVariant", label="Product Variant", tooltip="Chose variant which will be then used for " "product name, if " @@ -465,7 +459,6 @@ def create(self, subset_name, instance_data, pre_create_data): "timeline in order to export audio." ) - instance_data["clip_variant"] = pre_create_data["clip_variant"] instance_data["task"] = None # sort selected trackItems by @@ -486,20 +479,19 @@ def create(self, subset_name, instance_data, pre_create_data): "io.ayon.creators.hiero.plate": True, "io.ayon.creators.hiero.audio": pre_create_data.get("export_audio", False), } - enabled_creators = tuple(cre for cre, enabled in all_creators.items() if enabled) instances = [] - for idx, track_item in enumerate(sorted_selected_track_items): - - instance_data["clip_index"] = track_item.guid() + _instance_data = copy.deepcopy(instance_data) + _instance_data["clip_index"] = track_item.guid() # convert track item to timeline media pool item publish_clip = plugin.PublishClip( track_item, pre_create_data=pre_create_data, rename_index=idx, - data=instance_data) + data=_instance_data, + ) track_item = publish_clip.convert() if track_item is None: @@ -511,7 +503,7 @@ def create(self, subset_name, instance_data, pre_create_data): "Processing track item data: {} (index: {})".format( track_item, idx) ) - instance_data.update(publish_clip.tag_data) + _instance_data.update(publish_clip.tag_data) # Delete any existing instances previously generated for the clip. prev_tag = lib.get_trackitem_ayon_tag(track_item) @@ -527,11 +519,19 @@ def create(self, subset_name, instance_data, pre_create_data): creator.remove_instances(prev_instances) # Create new product(s) instances. - clip_instances = {} + shot_folder_path = _instance_data["folderPath"] + shot_instances = self.shot_instances.setdefault( + shot_folder_path, {}) shot_creator_id = "io.ayon.creators.hiero.shot" + all_creators["io.ayon.creators.hiero.shot"] = _instance_data.get( + "heroTrack", False) + enabled_creators = tuple( + cre for cre, enabled in all_creators.items() if enabled + ) + clip_instances = {} for creator_id in enabled_creators: creator = self.create_context.creators[creator_id] - sub_instance_data = copy.deepcopy(instance_data) + sub_instance_data = copy.deepcopy(_instance_data) shot_folder_path = sub_instance_data["folderPath"] # Shot creation @@ -539,36 +539,40 @@ def create(self, subset_name, instance_data, pre_create_data): track_item_duration = track_item.duration() workfileFrameStart = \ sub_instance_data["workfileFrameStart"] - sub_instance_data.update({ - "creator_attributes": { - "workfileFrameStart": \ - sub_instance_data["workfileFrameStart"], - "handleStart": sub_instance_data["handleStart"], - "handleEnd": sub_instance_data["handleEnd"], - "frameStart": workfileFrameStart, - "frameEnd": (workfileFrameStart + - track_item_duration), - "clipIn": track_item.timelineIn(), - "clipOut": track_item.timelineOut(), - "clipDuration": track_item_duration, - "sourceIn": track_item.sourceIn(), - "sourceOut": track_item.sourceOut(), - }, - "label": ( - f"{shot_folder_path} shot" - ), - }) + + sub_instance_data.update( + { + "variant": "main", + "productType": "shot", + "productName": "shotMain", + "creator_attributes": { + "workfileFrameStart": sub_instance_data[ + "workfileFrameStart" + ], + "handleStart": sub_instance_data["handleStart"], + "handleEnd": sub_instance_data["handleEnd"], + "frameStart": workfileFrameStart, + "frameEnd": (workfileFrameStart + track_item_duration), + "clipIn": track_item.timelineIn(), + "clipOut": track_item.timelineOut(), + "clipDuration": track_item_duration, + "sourceIn": track_item.sourceIn(), + "sourceOut": track_item.sourceOut(), + }, + "label": (f"{sub_instance_data['folderPath']} shotMain"), + } + ) # Plate, Audio # insert parent instance data to allow # metadata recollection as publish time. else: - parenting_data = clip_instances[shot_creator_id] + parenting_data = shot_instances[shot_creator_id] sub_instance_data.update({ "parent_instance_id": parenting_data["instance_id"], "label": ( - f"{shot_folder_path} " - f"{creator.product_type}" + f"{sub_instance_data['folderPath']} " + f"{sub_instance_data['productName']}" ), "creator_attributes": { "parentInstance": parenting_data["label"], @@ -578,7 +582,9 @@ def create(self, subset_name, instance_data, pre_create_data): instance = creator.create(sub_instance_data, None) instance.transient_data["track_item"] = track_item self._add_instance_to_context(instance) - clip_instances[creator_id] = instance.data_to_store() + instance_data_to_store = instance.data_to_store() + shot_instances[creator_id] = instance_data_to_store + clip_instances[creator_id] = instance_data_to_store lib.imprint( track_item, @@ -589,6 +595,10 @@ def create(self, subset_name, instance_data, pre_create_data): ) instances.append(instance) + # restore all caches + plugin.PublishClip.restore_all_caches() + self.shot_instances = {} + return instances def _create_and_add_instance(self, data, creator_id, @@ -701,7 +711,9 @@ def _collect_legacy_instance(self, track_item): workfileFrameStart = \ sub_instance_data["workfileFrameStart"] sub_instance_data.update({ - "label": f"{sub_instance_data['folderPath']} shot", + "label": ( + f"{sub_instance_data['folderPath']} " + f"{sub_instance_data['productName']}"), "variant": "main", "creator_attributes": { "workfileFrameStart": workfileFrameStart, @@ -738,15 +750,16 @@ def _collect_legacy_instance(self, track_item): for sub_creator_id in sub_creators: sub_instance_data = instance_data.copy() creator = self.create_context.creators[sub_creator_id] - sub_instance_data.update({ - "clip_variant": sub_instance_data["variant"], - "parent_instance_id": parenting_data["instance_id"], - "label": ( - f"{sub_instance_data['folderPath']} " - f"{creator.product_type}" - ), - "creator_attributes": { - "parentInstance": parenting_data["label"], + sub_instance_data.update( + { + "parent_instance_id": parenting_data["instance_id"], + "label": ( + f"{sub_instance_data['folderPath']} " + f"{sub_instance_data['productName']}" + ), + "creator_attributes": { + "parentInstance": parenting_data["label"], + } } }) From aa5bea3fa8a831641428a2206aee899e69f754e8 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 12 Nov 2024 10:36:43 +0100 Subject: [PATCH 4/6] Refactor product name generation logic in PublishClip class Simplify product name creation by using the 'variant' attribute instead of 'base_product_variant'. Update comparison to use 'variant' for consistency. --- client/ayon_hiero/api/plugin.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/client/ayon_hiero/api/plugin.py b/client/ayon_hiero/api/plugin.py index 92c33ce..6211ac7 100644 --- a/client/ayon_hiero/api/plugin.py +++ b/client/ayon_hiero/api/plugin.py @@ -824,14 +824,12 @@ def get(key): # build product name from layer name if self.base_product_variant == "": - self.base_product_variant = self.track_name self.variant = self.track_name else: self.variant = self.base_product_variant # create product for publishing - self.product_name = ( - f"{self.product_type}{self.base_product_variant.capitalize()}") + self.product_name = f"{self.product_type}{self.variant.capitalize()}" def _replace_hash_to_expression(self, name, text): """ Replace hash with number in correct padding. """ @@ -940,7 +938,7 @@ def _convert_to_tag_data(self): clip_product_name = self.product_name # in case track name and product name is the same then add - if self.base_product_variant == self.track_name: + if self.variant == self.track_name: clip_product_name = self.product_name # add track index in case duplicity of names in hero data From 447c2b8c3b8e2c7c95752d7c05e1be945ffdc645 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 12 Nov 2024 10:38:52 +0100 Subject: [PATCH 5/6] Refactor code for creating shot clip instance. - Removed unnecessary curly braces in dictionary. --- client/ayon_hiero/plugins/create/create_shot_clip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_hiero/plugins/create/create_shot_clip.py b/client/ayon_hiero/plugins/create/create_shot_clip.py index 3924ef1..73f251f 100644 --- a/client/ayon_hiero/plugins/create/create_shot_clip.py +++ b/client/ayon_hiero/plugins/create/create_shot_clip.py @@ -761,7 +761,7 @@ def _collect_legacy_instance(self, track_item): "parentInstance": parenting_data["label"], } } - }) + ) instance = creator.create(sub_instance_data, None) instance.transient_data["track_item"] = track_item From 299a05f8d9e10d36ae67a1403bf804670b4d3905 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 12 Nov 2024 15:36:31 +0100 Subject: [PATCH 6/6] Variant has to be also changed, not only product name --- client/ayon_hiero/api/plugin.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/ayon_hiero/api/plugin.py b/client/ayon_hiero/api/plugin.py index 6211ac7..041caae 100644 --- a/client/ayon_hiero/api/plugin.py +++ b/client/ayon_hiero/api/plugin.py @@ -936,6 +936,7 @@ def _convert_to_tag_data(self): f"{new_clip_name}{data_product_name}", []) clip_product_name = self.product_name + variant = self.variant # in case track name and product name is the same then add if self.variant == self.track_name: @@ -947,15 +948,17 @@ def _convert_to_tag_data(self): if clip_product_name in data_product_name: clip_product_name = ( f"{clip_product_name}{self.track_index}") + variant = f"{variant}{self.track_index}" # in case track clip product name had been already used # then add product name with clip index if clip_product_name in used_names_list: clip_product_name = ( f"{clip_product_name}{self.rename_index}") + variant = f"{variant}{self.rename_index}" _distrib_data["productName"] = clip_product_name - _distrib_data["variant"] = self.variant + _distrib_data["variant"] = variant # assign data to return hierarchy data to tag tag_instance_data = _distrib_data