Skip to content

Commit

Permalink
Build template with current and linked assets
Browse files Browse the repository at this point in the history
  • Loading branch information
BenoitConnan authored and ClementHector committed Feb 8, 2022
1 parent bda59a4 commit 4cb4e25
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 35 deletions.
55 changes: 28 additions & 27 deletions openpype/hosts/maya/plugins/init/template_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):

Expand All @@ -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
Expand All @@ -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
return user_data
93 changes: 85 additions & 8 deletions openpype/plugins/load/abstract_load_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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):
Expand Down Expand Up @@ -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"""
Expand All @@ -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):
Expand All @@ -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

0 comments on commit 4cb4e25

Please sign in to comment.