Last active
March 29, 2022 00:41
-
-
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"
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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