Source code for AL.omx.utils._nodes

# Copyright © 2023 Animal Logic. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.#
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging

from AL.omx.utils._stubs import cmds
from AL.omx.utils._stubs import om2

logger = logging.getLogger(__name__)


[docs] def partitionNameAndTrailingDigits(inputName): """Separate a node name into (name, trailingDigits) Args: inputName (str): the input name to partition. Returns: (str, int) if inputName has non-digit name and trailing digits. Examples: partitionNameAndTrailingDigits('') -> (None, None) partitionNameAndTrailingDigits('my_motion:name') -> ('my_motion:name', None) partitionNameAndTrailingDigits('2343') -> (None, 2343) partitionNameAndTrailingDigits('my_motion:name12') -> ('my_motion:name', 12) """ if not inputName: return (None, None) nameLen = len(inputName) digits = [] for i in range(nameLen - 1, -1, -1): if inputName[i].isdigit(): digits.append(inputName[i]) else: break digitLen = len(digits) if not digitLen: return (inputName, None) digit = int("".join(reversed(digits))) if not digitLen < nameLen: return (None, digit) baseName = inputName[: nameLen - digitLen] return (baseName, digit)
[docs] def closestAvailableNodeName(nodeName, _maximumAttempts=10000): """Return the closest node name that does not exist in Maya. Args: nodeName (str): the input name. _maximumAttempts (int, optional): The maximum attempts before get a node name that does not exists. Returns: str | None: Return the closest name that is available if nodeName is a valid Maya node name, otherwise None. Examples: Say in Maya scene we have nodes my_motion:ctrl, my_motion:ctrl1 closestAvailableNodeName('my_motion:ctrl') -> 'my_motion:ctrl2' """ if not nodeName: return None if not cmds.objExists(nodeName): if nodeName[0].isalpha() or nodeName[0] == "_": return nodeName return None baseName, digit = partitionNameAndTrailingDigits(nodeName) if not baseName: return None if digit is None: digit = 1 else: digit = digit + 1 i = 0 _maximumAttempts = max(_maximumAttempts, 0) while i < _maximumAttempts: newName = f"{baseName}{digit}" if not cmds.objExists(newName): return newName digit = digit + 1 i = i + 1 return closestAvailableNodeName(f"{nodeName}_1")
[docs] def findNode(nodeName): """ Find the dependency node MObject by name Args: nodeName (str): full or short name of the node Returns: om2.MObject if found or None otherwise """ # to avoid expensive check for existence, wrap with try except... # A cmds.objExists() test will return True for duplicate-named nodes, but it will # still raise run-time error when you add them to om2.MSelectionList. sl = om2.MSelectionList() try: sl.add(nodeName) except RuntimeError as e: logger.debug("Node %r does not exist.\n%s", nodeName, str(e)) return None if sl.length() == 1: node = sl.getDependNode(0) if node.isNull(): logger.error('Node: "%s" is Null.', nodeName) else: return node elif sl.length() > 1: logger.error('Node: "%s" is not unique.', nodeName) return None