diff --git a/openpype/hosts/maya/api/lib_template_builder.py b/openpype/hosts/maya/api/lib_template_builder.py index 84baa6199ce..d8ea5af6f60 100644 --- a/openpype/hosts/maya/api/lib_template_builder.py +++ b/openpype/hosts/maya/api/lib_template_builder.py @@ -4,18 +4,88 @@ from openpype.tools.utils.widgets import OptionDialog from avalon.maya.pipeline import get_main_window +# To change as enum +build_types = ["context_asset", "linked_asset", "all_assets"] + + +def get_placeholder_attributes(node): + return { + attr: cmds.getAttr("{}.{}".format(node, attr)) + for attr in cmds.listAttr(node, userDefined=True)} + def create_placeholder(): + args = placeholder_window() + + if not args: + return # operation canceled, no locator created + + placeholder = cmds.spaceLocator(name="_TEMPLATE_PLACEHOLDER_")[0] + + selection = cmds.ls(selection=True) + if selection: + cmds.parent(placeholder, selection[0]) + # custom arg parse to force empty data query + # and still imprint them on placeholder + # and getting items when arg is of type Enumerator + options = {str(arg): arg._data.get("items") or arg.read() + for arg in args if not type(arg) == qargparse.Separator} + imprint(placeholder, options) + # Some tweaks because imprint force enums to to default value so we get + # back arg read and force them to attributes + imprint_enum(placeholder, args) + + # Add helper attributes to keep placeholder info + cmds.addAttr( + placeholder, longName="parent", + hidden=True, dataType="string") + + +def update_placeholder(): + placeholder = cmds.ls(selection=True) + if len(placeholder) == 0: + raise ValueError("No node selected") + if len(placeholder) > 1: + raise ValueError("Too many selected nodes") + placeholder = placeholder[0] + + args = placeholder_window(get_placeholder_attributes(placeholder)) + if not args: + return # operation canceled + + options = {str(arg): arg._data.get("items") or arg.read() + for arg in args if not type(arg) == qargparse.Separator} + imprint(placeholder, options) + imprint_enum(placeholder, args) + + +def imprint_enum(placeholder, args): + """ + Imprint method doesn't act properly with enums. + Replacing the functionnality with this for now + """ + enum_values = {str(arg): arg.read() + for arg in args if arg._data.get("items")} + string_to_value_enum_table = { + build: i for i, build + in enumerate(build_types)} + for key, value in enum_values.items(): + cmds.setAttr( + placeholder + "." + key, + string_to_value_enum_table[value]) + + +def placeholder_window(options=None): + options = options or dict() dialog = OptionDialog(parent=get_main_window()) dialog.setWindowTitle("Create Placeholder") - build_types = ["context_asset", "linked_asset", "all_assets"] args = [ qargparse.Separator("Main attributes"), qargparse.Enum( "builder_type", label="Asset Builder Type", - default=0, + default=options.get("builder_type", 0), items=build_types, help="""Asset Builder Type Builder type describe what template loader will look for. @@ -30,17 +100,17 @@ def create_placeholder(): ), qargparse.String( "family", - default="", + default=options.get("family", ""), label="OpenPype Family", placeholder="ex: model, look ..."), qargparse.String( "representation", - default="", + default=options.get("representation", ""), label="OpenPype Representation", placeholder="ex: ma, abc ..."), qargparse.String( "loader", - default="", + default=options.get("loader", ""), label="Loader", placeholder="ex: ReferenceLoader, LightLoader ...", help="""Loader @@ -51,7 +121,7 @@ def create_placeholder(): """), qargparse.String( "loader_args", - default="", + default=options.get("loader_args", ""), label="Loader Arguments", placeholder='ex: {"camera":"persp", "lights":True}', help="""Loader @@ -62,7 +132,7 @@ def create_placeholder(): """), qargparse.Integer( "order", - default=0, + default=options.get("order", 0), min=0, max=999, label="Order", @@ -75,19 +145,19 @@ def create_placeholder(): "Optional attributes"), qargparse.String( "asset", - default="", + default=options.get("asset", ""), label="Asset filter", placeholder="regex filtering by asset name", help="Filtering assets by matching field regex to asset's name"), qargparse.String( "subset", - default="", + default=options.get("subset", ""), label="Subset filter", placeholder="regex filtering by subset name", help="Filtering assets by matching field regex to subset's name"), qargparse.String( "hierarchy", - default="", + default=options.get("hierarchy", ""), label="Hierarchy filter", placeholder="regex filtering by asset's hierarchy", help="Filtering assets by matching field asset's hierarchy") @@ -95,34 +165,6 @@ def create_placeholder(): dialog.create(args) if not dialog.exec_(): - return # operation canceled, no locator created + return None - # custom arg parse to force empty data query - # and still imprint them on placeholder - # and getting items when arg is of type Enumerator - # get maya selection - selection = cmds.ls(selection=True) - options = {str(arg): arg._data.get("items") or arg.read() - for arg in args if not type(arg) == qargparse.Separator} - placeholder = cmds.spaceLocator(name="_TEMPLATE_PLACEHOLDER_")[0] - # if something is selected parent the placeholder to the first selection - if selection: - cmds.parent(placeholder, selection[0]) - imprint(placeholder, options) - - # Some tweaks because imprint force enums to to default value so we get - # back arg read and force them to attributes - enum_values = {str(arg): arg.read() - for arg in args if arg._data.get("items")} - string_to_value_enum_table = { - build: i for i, build - in enumerate(build_types)} - for key, value in enum_values.items(): - cmds.setAttr( - placeholder + "." + key, - string_to_value_enum_table[value]) - - # Add helper attributes to keep placeholder info - cmds.addAttr( - placeholder, longName="parent", - hidden=True, dataType="string") + return args diff --git a/openpype/hosts/maya/api/template_loader.py b/openpype/hosts/maya/api/template_loader.py index 692668933c5..c600d646bf5 100644 --- a/openpype/hosts/maya/api/template_loader.py +++ b/openpype/hosts/maya/api/template_loader.py @@ -127,6 +127,11 @@ def parent_in_hierarchy(self, containers): refRoot = cmds.referenceQuery(root, n=True)[0] refRoot = cmds.listRelatives(refRoot, parent=True) or [refRoot] nodes_to_parent.extend(refRoot) + elif root in cmds.listSets(allSets=True): + if not cmds.sets(root, q=True): + return + else: + pass else: nodes_to_parent.append(root) @@ -161,6 +166,12 @@ def clean(self): if self.data['parent']: cmds.setAttr(node + '.parent', self.data['parent'], type='string') + holding_sets = cmds.listSets(object=node) + if not holding_sets: + return + for set in holding_sets: + cmds.sets(node, remove=set) + if cmds.listRelatives(node, p=True): node = cmds.parent(node, world=True)[0] cmds.sets(node, addElement=PLACEHOLDER_SET) @@ -168,11 +179,6 @@ def clean(self): cmds.setAttr(node+'.hiddenInOutliner', True) node = self.data['node'].rpartition('|')[2] - holding_sets = cmds.listSets(object=node) - if not holding_sets: - return - for set in holding_sets: - cmds.sets(node, remove=set) def convert_to_db_filters(self, current_asset, linked_asset): if self.data['builder_type'] == "context_asset": diff --git a/openpype/lib/abstract_template_loader.py b/openpype/lib/abstract_template_loader.py index 9ce3d52c4a0..bf8b6081006 100644 --- a/openpype/lib/abstract_template_loader.py +++ b/openpype/lib/abstract_template_loader.py @@ -2,6 +2,8 @@ import avalon from abc import ABCMeta, abstractmethod +import traceback + import six from openpype.settings import get_project_settings @@ -25,7 +27,7 @@ def update_representations(entities, entity): current = entities[entity['context']['asset']] incomming = entity entities[entity['context']['asset']] = max( - [current, incomming], + current, incomming, key= lambda entity: entity["context"].get("version")) return entities @@ -179,6 +181,8 @@ def template_path(self): solved_path = None while True: solved_path = anatomy.path_remapper(path) + if solved_path == None: + solved_path = path if solved_path == path: break path = solved_path @@ -244,17 +248,17 @@ def populate_template(self, override=None): loaders_by_name[placeholder.loader], last_representation['_id'], options=parse_loader_args(placeholder.data['loader_args'])) - if container: - placeholder.parent_in_hierarchy(container) - except Exception as err: + except Exception: bad_rep = last_representation self.log.warning( - "Got error trying to load {}:{} with {}\n" - "{}: {}".format( + "Got error trying to load {}:{} with {}\n\n" + "{}".format( bad_rep['context']['asset'], bad_rep['context']['subset'], placeholder.loader, - err.__class__.__name__, err)) + traceback.format_exc())) + if container: + placeholder.parent_in_hierarchy(container) placeholder.clean() def update_template(self):