From 55c3bdbd06f0baa06550654342ea7a66bd31c6e4 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 21 Dec 2023 17:30:37 +0800 Subject: [PATCH 1/8] add the contextmanager functions for 'reverting lock attributes' --- openpype/hosts/maya/api/lib.py | 139 +++++++++++++++++++-------------- 1 file changed, 79 insertions(+), 60 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index af726409d4..64cd5b6b6d 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -2565,6 +2565,66 @@ def bake_to_world_space(nodes, list: The newly created and baked node names. """ + @contextlib.contextmanager + def _revert_lock_attributes(node, new_node): + # Connect all attributes on the node except for transform + # attributes + attrs = _get_attrs(node) + attrs = set(attrs) - transform_attrs if attrs else [] + original_attrs_lock = {} + try: + for attr in attrs: + orig_node_attr = '{0}.{1}'.format(node, attr) + new_node_attr = '{0}.{1}'.format(new_node, attr) + original_attrs_lock[new_node_attr] = ( + cmds.getAttr(new_node_attr, lock=True) + ) + + # unlock to avoid connection errors + cmds.setAttr(new_node_attr, lock=False) + + cmds.connectAttr(orig_node_attr, + new_node_attr, + force=True) + yield + finally: + for attr, lock_state in original_attrs_lock.items(): + cmds.setAttr(attr, lock=lock_state) + + @contextlib.contextmanager + def _revert_lock_shape_attributes(node, new_node, shape): + # If shapes are also baked then connect those keyable attributes + if shape: + children_shapes = cmds.listRelatives(new_node, + children=True, + fullPath=True, + shapes=True) + if children_shapes: + orig_children_shapes = cmds.listRelatives(node, + children=True, + fullPath=True, + shapes=True) + original_shape_lock_attrs = {} + try: + for orig_shape, new_shape in zip(orig_children_shapes, + children_shapes): + attrs = _get_attrs(orig_shape) + for attr in attrs: + orig_node_attr = '{0}.{1}'.format(orig_shape, attr) + new_node_attr = '{0}.{1}'.format(new_shape, attr) + original_shape_lock_attrs[new_node_attr] = ( + cmds.getAttr(new_node_attr, lock=True) + ) + # unlock to avoid connection errors + cmds.setAttr(new_node_attr, lock=False) + + cmds.connectAttr(orig_node_attr, + new_node_attr, + force=True) + yield + finally: + for attr, lock_state in original_shape_lock_attrs.items(): + cmds.setAttr(attr, lock=lock_state) def _get_attrs(node): """Workaround for buggy shape attribute listing with listAttr""" @@ -2599,7 +2659,6 @@ def bake_to_world_space(nodes, world_space_nodes = [] with delete_after() as delete_bin: - # Create the duplicate nodes that are in world-space connected to # the originals for node in nodes: @@ -2610,69 +2669,29 @@ def bake_to_world_space(nodes, new_node = cmds.duplicate(node, name=new_name, renameChildren=True)[0] # noqa + with _revert_lock_attributes(node, new_node): + with _revert_lock_shape_attributes(node, new_node): + # Parent to world + if cmds.listRelatives(new_node, parent=True): + new_node = cmds.parent(new_node, world=True)[0] - # Connect all attributes on the node except for transform - # attributes - attrs = _get_attrs(node) - attrs = set(attrs) - transform_attrs if attrs else [] + # Unlock transform attributes so constraint can be created + for attr in transform_attrs: + cmds.setAttr('{0}.{1}'.format(new_node, attr), lock=False) - for attr in attrs: - orig_node_attr = '{0}.{1}'.format(node, attr) - new_node_attr = '{0}.{1}'.format(new_node, attr) + # Constraints + delete_bin.extend(cmds.parentConstraint(node, new_node, mo=False)) + delete_bin.extend(cmds.scaleConstraint(node, new_node, mo=False)) - # unlock to avoid connection errors - cmds.setAttr(new_node_attr, lock=False) + world_space_nodes.append(new_node) - cmds.connectAttr(orig_node_attr, - new_node_attr, - force=True) - - # If shapes are also baked then connect those keyable attributes - if shape: - children_shapes = cmds.listRelatives(new_node, - children=True, - fullPath=True, - shapes=True) - if children_shapes: - orig_children_shapes = cmds.listRelatives(node, - children=True, - fullPath=True, - shapes=True) - for orig_shape, new_shape in zip(orig_children_shapes, - children_shapes): - attrs = _get_attrs(orig_shape) - for attr in attrs: - orig_node_attr = '{0}.{1}'.format(orig_shape, attr) - new_node_attr = '{0}.{1}'.format(new_shape, attr) - - # unlock to avoid connection errors - cmds.setAttr(new_node_attr, lock=False) - - cmds.connectAttr(orig_node_attr, - new_node_attr, - force=True) - - # Parent to world - if cmds.listRelatives(new_node, parent=True): - new_node = cmds.parent(new_node, world=True)[0] - - # Unlock transform attributes so constraint can be created - for attr in transform_attrs: - cmds.setAttr('{0}.{1}'.format(new_node, attr), lock=False) - - # Constraints - delete_bin.extend(cmds.parentConstraint(node, new_node, mo=False)) - delete_bin.extend(cmds.scaleConstraint(node, new_node, mo=False)) - - world_space_nodes.append(new_node) - - bake(world_space_nodes, - frame_range=frame_range, - step=step, - simulation=simulation, - preserve_outside_keys=preserve_outside_keys, - disable_implicit_control=disable_implicit_control, - shape=shape) + bake(world_space_nodes, + frame_range=frame_range, + step=step, + simulation=simulation, + preserve_outside_keys=preserve_outside_keys, + disable_implicit_control=disable_implicit_control, + shape=shape) return world_space_nodes From ac7b2963dd928f04cce701e8d6ef3b74b26a02ed Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 21 Dec 2023 17:34:07 +0800 Subject: [PATCH 2/8] hound --- openpype/hosts/maya/api/lib.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 64cd5b6b6d..959a615ef9 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -2584,8 +2584,8 @@ def bake_to_world_space(nodes, cmds.setAttr(new_node_attr, lock=False) cmds.connectAttr(orig_node_attr, - new_node_attr, - force=True) + new_node_attr, + force=True) yield finally: for attr, lock_state in original_attrs_lock.items(): @@ -2596,18 +2596,18 @@ def bake_to_world_space(nodes, # If shapes are also baked then connect those keyable attributes if shape: children_shapes = cmds.listRelatives(new_node, - children=True, - fullPath=True, - shapes=True) + children=True, + fullPath=True, + shapes=True) if children_shapes: orig_children_shapes = cmds.listRelatives(node, - children=True, - fullPath=True, - shapes=True) + children=True, + fullPath=True, + shapes=True) original_shape_lock_attrs = {} try: for orig_shape, new_shape in zip(orig_children_shapes, - children_shapes): + children_shapes): attrs = _get_attrs(orig_shape) for attr in attrs: orig_node_attr = '{0}.{1}'.format(orig_shape, attr) @@ -2619,8 +2619,8 @@ def bake_to_world_space(nodes, cmds.setAttr(new_node_attr, lock=False) cmds.connectAttr(orig_node_attr, - new_node_attr, - force=True) + new_node_attr, + force=True) yield finally: for attr, lock_state in original_shape_lock_attrs.items(): From a75ff0f71aab21daa86ffd40ce45ff0e8b9aee20 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 21 Dec 2023 17:36:35 +0800 Subject: [PATCH 3/8] hound --- openpype/hosts/maya/api/lib.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 959a615ef9..3bc8b67a81 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -2671,27 +2671,30 @@ def bake_to_world_space(nodes, renameChildren=True)[0] # noqa with _revert_lock_attributes(node, new_node): with _revert_lock_shape_attributes(node, new_node): - # Parent to world + # Parent to world if cmds.listRelatives(new_node, parent=True): new_node = cmds.parent(new_node, world=True)[0] # Unlock transform attributes so constraint can be created for attr in transform_attrs: - cmds.setAttr('{0}.{1}'.format(new_node, attr), lock=False) + cmds.setAttr( + '{0}.{1}'.format(new_node, attr), lock=False) # Constraints - delete_bin.extend(cmds.parentConstraint(node, new_node, mo=False)) - delete_bin.extend(cmds.scaleConstraint(node, new_node, mo=False)) + delete_bin.extend( + cmds.parentConstraint(node, new_node, mo=False)) + delete_bin.extend( + cmds.scaleConstraint(node, new_node, mo=False)) world_space_nodes.append(new_node) bake(world_space_nodes, - frame_range=frame_range, - step=step, - simulation=simulation, - preserve_outside_keys=preserve_outside_keys, - disable_implicit_control=disable_implicit_control, - shape=shape) + frame_range=frame_range, + step=step, + simulation=simulation, + preserve_outside_keys=preserve_outside_keys, + disable_implicit_control=disable_implicit_control, + shape=shape) return world_space_nodes From 1a39a5cc99ca18fcd2354a5e5d8e928ce67bc4df Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Fri, 22 Dec 2023 11:09:46 +0100 Subject: [PATCH 4/8] Unlock attributes only during the bake context, make sure attributes are relocked after to preserve the lock state of the original node being baked --- openpype/hosts/maya/api/lib.py | 171 +++++++++++++++++---------------- 1 file changed, 87 insertions(+), 84 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 3bc8b67a81..63f0812785 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -2566,68 +2566,36 @@ def bake_to_world_space(nodes, """ @contextlib.contextmanager - def _revert_lock_attributes(node, new_node): - # Connect all attributes on the node except for transform - # attributes - attrs = _get_attrs(node) - attrs = set(attrs) - transform_attrs if attrs else [] - original_attrs_lock = {} + def _unlock_attr(attr): + """Unlock attribute during context if it is locked""" + if not cmds.getAttr(attr, lock=True): + # If not locked, do nothing + yield + return try: - for attr in attrs: - orig_node_attr = '{0}.{1}'.format(node, attr) - new_node_attr = '{0}.{1}'.format(new_node, attr) - original_attrs_lock[new_node_attr] = ( - cmds.getAttr(new_node_attr, lock=True) - ) - - # unlock to avoid connection errors - cmds.setAttr(new_node_attr, lock=False) - - cmds.connectAttr(orig_node_attr, - new_node_attr, - force=True) + cmds.setAttr(attr, lock=False) yield finally: - for attr, lock_state in original_attrs_lock.items(): - cmds.setAttr(attr, lock=lock_state) - - @contextlib.contextmanager - def _revert_lock_shape_attributes(node, new_node, shape): - # If shapes are also baked then connect those keyable attributes - if shape: - children_shapes = cmds.listRelatives(new_node, - children=True, - fullPath=True, - shapes=True) - if children_shapes: - orig_children_shapes = cmds.listRelatives(node, - children=True, - fullPath=True, - shapes=True) - original_shape_lock_attrs = {} - try: - for orig_shape, new_shape in zip(orig_children_shapes, - children_shapes): - attrs = _get_attrs(orig_shape) - for attr in attrs: - orig_node_attr = '{0}.{1}'.format(orig_shape, attr) - new_node_attr = '{0}.{1}'.format(new_shape, attr) - original_shape_lock_attrs[new_node_attr] = ( - cmds.getAttr(new_node_attr, lock=True) - ) - # unlock to avoid connection errors - cmds.setAttr(new_node_attr, lock=False) - - cmds.connectAttr(orig_node_attr, - new_node_attr, - force=True) - yield - finally: - for attr, lock_state in original_shape_lock_attrs.items(): - cmds.setAttr(attr, lock=lock_state) + cmds.setAttr(attr, lock=True) def _get_attrs(node): - """Workaround for buggy shape attribute listing with listAttr""" + """Workaround for buggy shape attribute listing with listAttr + + This will only return keyable settable attributes that have an + incoming connections (those that have a reason to be baked). + + Technically this *may* fail to return attributes driven by complex + expressions for which maya makes no connections, e.g. doing actual + `setAttr` calls in expressions. + + Arguments: + node (str): The node to list attributes for. + + Returns: + list: Keyable attributes with incoming connections. + The attribute may be locked. + + """ attrs = cmds.listAttr(node, write=True, scalar=True, @@ -2652,13 +2620,14 @@ def bake_to_world_space(nodes, return valid_attrs - transform_attrs = set(["t", "r", "s", - "tx", "ty", "tz", - "rx", "ry", "rz", - "sx", "sy", "sz"]) + transform_attrs = {"t", "r", "s", + "tx", "ty", "tz", + "rx", "ry", "rz", + "sx", "sy", "sz"} world_space_nodes = [] - with delete_after() as delete_bin: + with contextlib.ExitStack() as stack: + delete_bin = stack.enter_context(delete_after()) # Create the duplicate nodes that are in world-space connected to # the originals for node in nodes: @@ -2669,32 +2638,66 @@ def bake_to_world_space(nodes, new_node = cmds.duplicate(node, name=new_name, renameChildren=True)[0] # noqa - with _revert_lock_attributes(node, new_node): - with _revert_lock_shape_attributes(node, new_node): - # Parent to world - if cmds.listRelatives(new_node, parent=True): - new_node = cmds.parent(new_node, world=True)[0] - # Unlock transform attributes so constraint can be created - for attr in transform_attrs: - cmds.setAttr( - '{0}.{1}'.format(new_node, attr), lock=False) + # Parent new node to world + if cmds.listRelatives(new_node, parent=True): + new_node = cmds.parent(new_node, world=True)[0] - # Constraints - delete_bin.extend( - cmds.parentConstraint(node, new_node, mo=False)) - delete_bin.extend( - cmds.scaleConstraint(node, new_node, mo=False)) + # Temporarily unlock and passthrough connect all attributes + # so we can bake them over time + # Skip transform attributes because we will constrain them later + attrs = set(_get_attrs(node)) - transform_attrs + for attr in attrs: + orig_node_attr = "{}.{}".format(node, attr) + new_node_attr = "{}.{}".format(new_node, attr) - world_space_nodes.append(new_node) + # unlock during context to avoid connection errors + stack.enter_context(_unlock_attr(new_node_attr)) + cmds.connectAttr(orig_node_attr, + new_node_attr, + force=True) - bake(world_space_nodes, - frame_range=frame_range, - step=step, - simulation=simulation, - preserve_outside_keys=preserve_outside_keys, - disable_implicit_control=disable_implicit_control, - shape=shape) + # If shapes are also baked then also temporarily unlock and + # passthrough connect all shape attributes for baking + if shape: + children_shapes = cmds.listRelatives(new_node, + children=True, + fullPath=True, + shapes=True) + if children_shapes: + orig_children_shapes = cmds.listRelatives(node, + children=True, + fullPath=True, + shapes=True) + for orig_shape, new_shape in zip(orig_children_shapes, + children_shapes): + attrs = _get_attrs(orig_shape) + for attr in attrs: + orig_node_attr = "{}.{}".format(orig_shape, attr) + new_node_attr = "{}.{}".format(new_shape, attr) + + # unlock during context to avoid connection errors + stack.enter_context(_unlock_attr(new_node_attr)) + cmds.connectAttr(orig_node_attr, + new_node_attr, + force=True) + + # Constraint transforms + for attr in transform_attrs: + transform_attr = "{}.{}".format(new_node, attr) + stack.enter_context(_unlock_attr(transform_attr)) + delete_bin.extend(cmds.parentConstraint(node, new_node, mo=False)) + delete_bin.extend(cmds.scaleConstraint(node, new_node, mo=False)) + + world_space_nodes.append(new_node) + + bake(world_space_nodes, + frame_range=frame_range, + step=step, + simulation=simulation, + preserve_outside_keys=preserve_outside_keys, + disable_implicit_control=disable_implicit_control, + shape=shape) return world_space_nodes From eaa0a8f60eeac2e3441d2bf83aa395dca4222326 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 22 Dec 2023 22:21:47 +0800 Subject: [PATCH 5/8] make sure not overindented when calling bake function --- openpype/hosts/maya/api/lib.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 63f0812785..06cefbf793 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -2691,13 +2691,13 @@ def bake_to_world_space(nodes, world_space_nodes.append(new_node) - bake(world_space_nodes, - frame_range=frame_range, - step=step, - simulation=simulation, - preserve_outside_keys=preserve_outside_keys, - disable_implicit_control=disable_implicit_control, - shape=shape) + bake(world_space_nodes, + frame_range=frame_range, + step=step, + simulation=simulation, + preserve_outside_keys=preserve_outside_keys, + disable_implicit_control=disable_implicit_control, + shape=shape) return world_space_nodes From 9be69c3f304428792a454f1831a6d090ddf86231 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 4 Jan 2024 00:25:34 +0800 Subject: [PATCH 6/8] implement exitstack functions from exitstack.py --- openpype/hosts/maya/api/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index eb83a44cde..da34896c3f 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -2839,7 +2839,7 @@ def bake_to_world_space(nodes, "sx", "sy", "sz"} world_space_nodes = [] - with contextlib.ExitStack() as stack: + with ExitStack() as stack: delete_bin = stack.enter_context(delete_after()) # Create the duplicate nodes that are in world-space connected to # the originals From 5bdad2b37c89272ff29885bc03eabadce907c0be Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 16 Jan 2024 21:36:04 +0800 Subject: [PATCH 7/8] bug fix the limit groups from maya deadline settings unabled to be set by the username and error out --- server_addon/deadline/server/settings/publish_plugins.py | 2 +- server_addon/deadline/server/version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server_addon/deadline/server/settings/publish_plugins.py b/server_addon/deadline/server/settings/publish_plugins.py index a989f3ad9d..dfb30f9b41 100644 --- a/server_addon/deadline/server/settings/publish_plugins.py +++ b/server_addon/deadline/server/settings/publish_plugins.py @@ -87,7 +87,7 @@ class MayaSubmitDeadlineModel(BaseSettingsModel): title="Disable Strict Error Check profiles" ) - @validator("limit", "scene_patches") + @validator("scene_patches") def validate_unique_names(cls, value): ensure_unique_names(value) return value diff --git a/server_addon/deadline/server/version.py b/server_addon/deadline/server/version.py index 0a8da88258..f1380eede2 100644 --- a/server_addon/deadline/server/version.py +++ b/server_addon/deadline/server/version.py @@ -1 +1 @@ -__version__ = "0.1.6" +__version__ = "0.1.7" From b29dee59fadbaa59876d0684eb0c30df5bba0681 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 16 Jan 2024 16:48:35 +0100 Subject: [PATCH 8/8] add addons dir only if exists --- openpype/modules/base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/modules/base.py b/openpype/modules/base.py index 1a2513b4b4..41be2998f9 100644 --- a/openpype/modules/base.py +++ b/openpype/modules/base.py @@ -542,7 +542,8 @@ def _load_modules(): module_dirs.insert(0, current_dir) addons_dir = os.path.join(os.path.dirname(current_dir), "addons") - module_dirs.append(addons_dir) + if os.path.exists(addons_dir): + module_dirs.append(addons_dir) ignored_host_names = set(IGNORED_HOSTS_IN_AYON) ignored_current_dir_filenames = set(IGNORED_DEFAULT_FILENAMES)