Skip to content

Instantly share code, notes, and snippets.

@MongoWobbler
Last active March 29, 2022 00:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MongoWobbler/7ac66d1f63bc1b1042bdbce3ca48ea75 to your computer and use it in GitHub Desktop.
Save MongoWobbler/7ac66d1f63bc1b1042bdbce3ca48ea75 to your computer and use it in GitHub Desktop.
Function and decorator to avoid writing two functions when arguments are swappable, such as "left" and/or "right"
import re
import pymel.core as pm
left_name = 'Left '
left_suffix = '_l'
left_tag = '_l_'
right_name = 'Right '
right_suffix = '_r'
right_tag = '_r_'
def swapText(text, first, second):
"""
Swaps the given first and seconds strings with each other in the given text.
Args:
text (string): Text to look for given first and second string to swap with each other.
first (string): Text to swap with the second string.
second (string): Text to swap with the first string.
Returns:
(string): Text with strings swapped if they were found. Else same text as before.
"""
return re.sub(r'{a}|{b}'.format(a=first, b=second), lambda w: first if w.group() == second else second, text)
def _validateMirrorArg(arg, success):
"""
Gets the given arg as the mirror if a mirror exists.
Args:
arg (any): Can only mirror strings, PyNodes, and lists.
success (list): List with a single bool in it to let calling function know if mirror was sucessful or not.
Returns:
(any): Given arg mirrored if possible, if not, then original arg.
"""
if not isinstance(arg, (str, pm.PyNode, list)):
return arg
if isinstance(arg, list):
new_arg = []
for item in arg:
new_arg.append(_validateMirrorArg(item, success))
return new_arg
if isinstance(arg, pm.PyNode):
arg = arg.name()
# swapping out full names
if left_name in arg or right_name in arg:
success[0] = True
arg = swapText(arg, left_name, right_name)
if arg.endswith((left_suffix, right_suffix)):
success[0] = True
return swapText(arg, left_suffix, right_suffix)
if left_tag in arg or right_tag in arg:
success[0] = True
return swapText(arg, left_tag, right_tag)
return arg
def mirror(method, *args, **kwargs):
"""
Mirrors the given method by swapping the configured sides with each other from all the valid args and kwargs.
Method will always execute first regardless of sides found.
Args:
method (method): Method to execute AND execute mirrored IF sides are found.
Returns:
(any): Results of executing method.
"""
results = method(*args, **kwargs)
found_sides = []
new_args = []
new_kwargs = {}
for arg in args:
found_side = [False] # found side bool passed within a list to be used as a reference (hack-ish)
new_arg = _validateMirrorArg(arg, found_side)
new_arg = new_arg if found_side[0] else arg
new_args.append(new_arg)
found_sides.append(found_side[0])
for key, value in kwargs.items():
found_side = [False]
new_value = _validateMirrorArg(value, found_side)
new_value = new_value if found_side[0] else value
new_kwargs[key] = new_value
found_sides.append(found_side[0])
success = any(found_sides) # if any sides are found, then mirror
# run the method with mirrored args and kwargs
if success:
method(*new_args, **new_kwargs)
return results
def _mirror(method):
"""
Decorator for executing the given method with the mirrored sides suffix as args and kwargs.
Method must be part of a class, and class must have a self.is_mirroring variable.
Args:
method (method): Will execute with sides flipped.
"""
def wrapper(self, *args, **kwargs):
if not self.is_mirroring: # execute function normally if its not mirroring
return method(self, *args, **kwargs)
self.is_mirroring = False # must turn off mirroring so that other functions inside method don't get mirrored.
args = list(args)
args.insert(0, self)
results = mirror(method, *args, **kwargs)
self.is_mirroring = True
return results
return wrapper
def _ignoreMirror(method):
"""
Convenience decorator to mark a function as not mirror-able even is self.is_mirroring is True.
"""
def wrapper(self, *args, **kwargs):
is_mirroring = self.is_mirroring
self.is_mirroring = False
results = method(self, *args, **kwargs)
self.is_mirroring = is_mirroring
return results
return wrapper
# Example class implementing the _mirror decorator
class Rig(object):
def __init__(self, mirrored=False):
self.is_mirroring = mirrored
@_mirror # decorator that will automatically attempt to mirror printString when its called!
def printString(self, to_print):
print(to_print)
# Examples
if __name__ == '__main__':
rig = Rig(mirrored=True)
rig.printString('Hello, there are no sides in this string.')
rig.printString("There is a Left side here, so function will repeat.")
mirror(print, 'this time using a function with the suffix _r')
rig.is_mirroring = False # turning off mirroring
rig.printString("This function will execute but won't mirror even with this Left here.")
# Results:
# >>> Hello, there are no sides in this string.
# >>> There is a Left side here, so function will repeat.
# >>> There is a Right side here, so function will repeat.
# >>> this time using a function with the suffix _r
# >>> this time using a function with the suffix _l
# >>> This function will execute but won't mirror even with this Left here.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment