From 3db5df1a6f613d89bc6b3f4e432722b06645af64 Mon Sep 17 00:00:00 2001 From: BenoitConnan Date: Wed, 27 Oct 2021 10:21:19 +0200 Subject: [PATCH] Build template with current and linked assets --- .../maya/plugins/init/template_loader.py | 55 +++++------ .../plugins/load/abstract_load_template.py | 93 +++++++++++++++++-- 2 files changed, 113 insertions(+), 35 deletions(-) diff --git a/openpype/hosts/maya/plugins/init/template_loader.py b/openpype/hosts/maya/plugins/init/template_loader.py index 0bb6c3beb37..fd6eaeaf72c 100644 --- a/openpype/hosts/maya/plugins/init/template_loader.py +++ b/openpype/hosts/maya/plugins/init/template_loader.py @@ -6,7 +6,7 @@ def init_cmds(): global cmds cmds = cmds or importlib.import_module('maya').cmds -ATTRIBUTES = ['asset_type', 'representation', 'families', 'repre_name', 'asset', 'hierarchy', 'loader', 'order'] +ATTRIBUTES = ['builder_type', 'representation', 'families', 'repre_name', 'asset', 'hierarchy', 'loader', 'order'] class TemplateLoader(AbstractTemplateLoader): @@ -17,43 +17,53 @@ def __init__(self): def import_template(self, path): self.newNodes = cmds.file(path, i=True, returnNewNodes=True) - - def get_template_nodes(self): - return self._get_all_nodes_with_attribute('asset_type') + @staticmethod + def get_template_nodes(): + attribute_list = cmds.ls('*.builder_type', long=True) + return [attr.rpartition('.')[0] for attr in attribute_list] def placeholderize(self, node): return self._get_all_user_data_on_node(node) + def is_placeholder_context(self, placeholder): + return placeholder['builder_type'] == "context_asset" + @staticmethod def get_valid_representations_id_for_placeholder(representations, placeholder): + if len(representations) < 1: + return [] + repres = [r['_id'] for rep in representations for r in rep if ( placeholder['families'] == r['context']['family'] and placeholder['repre_name'] == r['context']['representation'] and placeholder['representation'] == r['context']['subset'] )] - if len(repres) <1: - raise ValueError("No representation found for asset {} with:\n" - "family : {}\n" + if len(repres) < 1: + raise ValueError("No representation found for {} with:\n" "rerpresentation : {}\n" - "subset : {}\n".format( - placeholder['name'], - placeholder['family'], - placeholder['representation_type'], - placeholder['subset'] + "representation name : {}\n" + "Are you sure representations have been published ?".format( + placeholder['builder_type'], + placeholder['representation'], + placeholder['repre_name'] ) ) return repres @staticmethod - def switch(container, placeholder): + def switch(containers, placeholder): node = placeholder['node'] nodeParent = cmds.ls(node, long=True)[0].rpartition('|')[0] if cmds.nodeType(node) != 'transform': nodeParent = nodeParent.rpartition('|')[0] - #TODO: Find a prettier solution - child = map(lambda x: x.replace('__', '_:').replace('_CON', ''), container) + + child = map(lambda x: x.replace('__', '_:').replace('_CON', ''), containers) cmds.parent(child, nodeParent) + + @staticmethod + def clean_placeholder(placeholder): + node = placeholder['node'] cmds.delete(node) @staticmethod @@ -69,20 +79,11 @@ def is_valid_placeholder(node): def _get_placeholder_loader_name(placeholder): return placeholder['loader'] - @staticmethod - def _get_all_nodes_with_attribute(attribute_name): - attribute_list = cmds.ls('*.{}'.format(attribute_name), long=True) - return [attr.rpartition('.')[0] for attr in attribute_list] - @staticmethod def _get_node_data(node): - all_attributes = cmds.listAttr(node, userDefined=True) - - user_data = {} - for attr in all_attributes: - if not attr in ATTRIBUTES: - continue + user_data = dict() + for attr in ATTRIBUTES: user_data[attr] = cmds.getAttr('{}.{}'.format(node, attr), asString=True) user_data['node'] = node - return user_data \ No newline at end of file + return user_data diff --git a/openpype/plugins/load/abstract_load_template.py b/openpype/plugins/load/abstract_load_template.py index 1107bf077d0..ce8d8b01a25 100644 --- a/openpype/plugins/load/abstract_load_template.py +++ b/openpype/plugins/load/abstract_load_template.py @@ -116,9 +116,41 @@ def get_loader_by_name(): ############################## class AbstractTemplateLoader(object): + """ + Property returning template path. Avoiding getter. + Getting template path from open pype settings + bassing on current avalon session + and solving the path variables if needed. + + Properties: + template_path (str) : + + Methods: + get_representations + get_valid_representations_id_for_placeholder + validate_representation + _get_node_data + import_template + switch + get_template_nodes + """ @property def template_path(self): + """ + Property returning template path. Avoiding getter. + Getting template path from open pype settings + bassing on current avalon session + and solving the path variables if needed. + + Returns: + str: Solved template path + + Raises: + ValueError: No profile found from settings for current avalon session + KeyError: Could not solve path because a key does not exists in avalon context + IOError: Solved path does not exists on current filesystem + """ project = avalon.io.Session["AVALON_PROJECT"] anatomy = Anatomy(project) project_settings = get_project_settings(project) @@ -135,10 +167,10 @@ def template_path(self): solved_path = os.path.normpath(anatomy.path_remapper(path)) except KeyError as missing_key: - raise KeyError("Could not solve key '{}' in path '{}'".format(missing_key, path)) + raise KeyError("Could not solve key '{}' in template path '{}'".format(missing_key, path)) if not os.path.exists(solved_path): - raise IOError("Template '{}' does not exists.".format(path)) + raise IOError("Template found in openPype settings for task '{}' with DCC '{}' does not exists. (Not found : {})".format(current_task, current_dcc, solved_path)) return solved_path def __init__(self): @@ -173,13 +205,14 @@ def __init__(self): for placeholder in placeholders: loader_name = self._get_placeholder_loader_name(placeholder) - representations = current_representations if placeholder else linked_representations + representations = current_representations if self.is_placeholder_context(placeholder) else linked_representations for representation in self.get_valid_representations_id_for_placeholder(representations, placeholder): container = avalon.api.load( loaders_by_name[loader_name], representation ) self.switch(container, placeholder) + self.clean_placeholder(placeholder) def get_representations(self, entities): """Parse avalon entities to get representations""" @@ -188,15 +221,47 @@ def get_representations(self, entities): if entity['asset_entity']['_id']] @staticmethod - def get_valid_representations_id(self, representation): + def get_valid_representations_id_for_placeholder(self, representation): + """ + filter representations + + Arguments : + representation [dict()]: + + Returns: + representations [dict()] : + """ raise NotImplementedError @staticmethod def validate_representation(representation, placeholder): + """ + Property returning template path. Avoiding getter. + Getting template path from open pype settings + bassing on current avalon session + and solving the path variables if needed. + + Returns: + str: Solved template path + + Raises: + ValueError: No profile found from settings for current avalon session + KeyError: Could not solve path because a key does not exists in avalon context + IOError: Solved path does not exists on current filesystem + """ raise NotImplementedError @staticmethod def _get_node_data(self, node): + """ + extract data from node + + Arguments: + NodeClass: Your class + + Returns: + str: Solved template path + """ raise NotImplementedError def import_template(self, template_path): @@ -208,15 +273,27 @@ def import_template(self, template_path): """ raise NotImplementedError - def switch(self, container, node): + def switch(self, containers, placeholder): """ - Import template in dcc + Load containers for placeholder Args: - container (str): fullpath to current task and dcc's template file - node (): + containers (): + placeholder (): + + Returns : + None """ raise NotImplementedError def get_template_nodes(self): + """ + Property returning template path. forbidding user to set. + Getting template path from open pype settings + bassing on current avalon session + and solving the path variables if needed. + + Returns: + str: Solved template path + """ raise NotImplementedError